Can You Skip sqrt for Faster Collision Detection in JavaScript?
The Problem
I was building a canvas game with collision detection. My game loop was struggling—60 FPS was dropping to 30 FPS when I had more than 200 objects on screen. The profiler pointed directly at my distance calculations.
function checkCollision(obj1, obj2, radius) { const dx = obj1.x - obj2.x; const dy = obj1.y - obj2.y; const distance = Math.hypot(dx, dy); return distance < radius;}With 200 objects checking collisions against each other, I was doing ~20,000 Math.hypot() calls per frame. At 60 FPS, that’s 1.2 million calls per second. The sqrt operation inside Math.hypot() was killing my performance.
The Discovery
I posted about this on Reddit and got a response that changed everything:
“For distance comparisons (like collision detection), you can skip the sqrt entirely and compare squared distances. No sqrt, no hypot, just multiplication and comparison. This is the standard trick in game dev and it makes a measurable difference in hot loops” — tokagemushi
Another user confirmed:
“If you’re just comparing relative hypotenuse lengths, it might be faster to just compare the sums of the squares” — rcfox
The math is straightforward. For any positive values a and b:
a < b is equivalent to a² < b²Since I only cared whether distance < radius, not the actual distance value, I could compare squared distances directly and skip the expensive sqrt entirely.
The Solution
I rewrote my collision check:
function checkCollision(obj1, obj2, radius) { const dx = obj1.x - obj2.x; const dy = obj1.y - obj2.y; const distanceSquared = dx * dx + dy * dy; const radiusSquared = radius * radius; return distanceSquared < radiusSquared;}No Math.hypot(). No Math.sqrt(). Just three multiplications and one comparison.
Why This Works
The Mathematical Reasoning
The distance formula is:
distance = sqrt(dx² + dy²)For collision detection, I only need to know if distance < radius. Squaring both sides:
distance² < radius²dx² + dy² < radius²The comparison result is identical, but I’ve eliminated the sqrt operation entirely.
CPU Cost Comparison
Operation CPU Cycles (approximate)─────────────────────────────────────────────Multiplication ~3 cyclesAddition ~1 cycleComparison ~1 cyclesqrt/hypot ~10-50 cycles (varies by implementation)My optimized version uses ~10 cycles total. The naive version with Math.hypot() uses ~50+ cycles. That’s a 5x improvement per collision check.
Benchmark Results
I created a benchmark to measure the actual difference:
const iterations = 10_000_000;const obj1 = { x: 100, y: 200 };const obj2 = { x: 103, y: 204 };const radius = 10;
// Test 1: Math.hypotconsole.time('Math.hypot');for (let i = 0; i < iterations; i++) { const dx = obj1.x - obj2.x; const dy = obj1.y - obj2.y; if (Math.hypot(dx, dy) < radius) { /* collision */ }}console.timeEnd('Math.hypot');
// Test 2: Squared distance (OPTIMIZED)console.time('Squared distance');const radiusSquared = radius * radius;for (let i = 0; i < iterations; i++) { const dx = obj1.x - obj2.x; const dy = obj1.y - obj2.y; if (dx * dx + dy * dy < radiusSquared) { /* collision */ }}console.timeEnd('Squared distance');Results on V8 (Chrome/Node.js):
Math.hypot: ~3000msSquared distance: ~200ms
Speedup: 15x fasterReal-World Application: Particle System
Here’s how I applied this to a particle collision system:
class ParticleSystem { constructor(particles) { this.particles = particles; this.collisionRadius = 5; this.collisionRadiusSquared = 25; // Pre-calculate! }
checkCollisions() { for (let i = 0; i < this.particles.length; i++) { for (let j = i + 1; j < this.particles.length; j++) { const p1 = this.particles[i]; const p2 = this.particles[j]; const dx = p1.x - p2.x; const dy = p1.y - p2.y;
if (dx * dx + dy * dy < this.collisionRadiusSquared) { this.resolveCollision(p1, p2); } } } }}The key optimization is pre-computing collisionRadiusSquared once at initialization, not in the hot loop.
Real-World Application: Bullet-to-Enemy Collision
For a game loop running at 60 FPS:
class GameEngine { constructor() { this.bullets = []; this.enemies = []; this.hitRadius = 20; this.hitRadiusSquared = 400; // Pre-calculate }
update() { for (const bullet of this.bullets) { for (const enemy of this.enemies) { const dx = bullet.x - enemy.x; const dy = bullet.y - enemy.y;
if (dx * dx + dy * dy < this.hitRadiusSquared) { this.handleHit(bullet, enemy); } } } }}With 50 bullets and 200 enemies (10,000 checks per frame), this optimization saved ~1.5ms per frame—enough to maintain 60 FPS.
Common Mistakes
Mistake 1: Comparing Mixed Squared/Unsquared Values
// WRONG: Comparing squared distance with unsquared radiusif (dx * dx + dy * dy < radius) { } // Bug!
// CORRECT: Compare squared with squaredif (dx * dx + dy * dy < radius * radius) { }Mistake 2: Recomputing Squared Radius in Hot Loops
// SLOW: Recomputing every framefunction checkCollision(p, e) { const radiusSq = (p.radius + e.radius) ** 2; // Don't do this! return dx * dx + dy * dy < radiusSq;}
// FAST: Pre-computed and cachedclass Entity { constructor(radius) { this.radius = radius; this.radiusSquared = radius * radius; // Compute once }}Mistake 3: Using Squared Distance When You Need Actual Distance
// WRONG: Need actual distance for physics calculationsfunction bounceOffWall(ball, wall) { const dx = ball.x - wall.x; const dy = ball.y - wall.y; const distanceSquared = dx * dx + dy * dy; ball.velocity = reflect(distanceSquared); // Wrong dimension!}
// CORRECT: Use Math.hypot when you need the actual valuefunction bounceOffWall(ball, wall) { const dx = ball.x - wall.x; const dy = ball.y - wall.y; const distance = Math.hypot(dx, dy); const normal = { x: dx / distance, y: dy / distance }; ball.velocity = reflect(ball.velocity, normal);}Works in 3D Too
The squared distance trick extends to any dimension:
function checkCollision3D(obj1, obj2, radiusSquared) { const dx = obj1.x - obj2.x; const dy = obj1.y - obj2.y; const dz = obj1.z - obj2.z; return dx * dx + dy * dy + dz * dz < radiusSquared;}Performance Impact Summary
┌─────────────────────────────────┬───────────────────────────────────────┐│ Metric │ Impact │├─────────────────────────────────┼───────────────────────────────────────┤│ Speedup per check │ 10-15x faster than Math.hypot() ││ CPU cycles saved │ ~40 cycles per collision check ││ Memory overhead │ None (fewer function calls) ││ Code complexity │ Slightly more verbose ││ Applicability │ Distance comparisons only │└─────────────────────────────────┴───────────────────────────────────────┘When to Use This Technique
Use squared distance comparison when:
- Collision detection between objects
- Range-based entity queries (e.g., “find enemies within 100px”)
- Proximity triggers in game logic
- Any “is distance less than X” comparison
Keep using Math.hypot() or Math.sqrt() when:
- You need to display the distance value
- Physics calculations require actual distance
- Movement speed depends on distance
- You’re debugging and need readable output
Summary
In this post, I explained how to optimize collision detection by comparing squared distances instead of using Math.sqrt() or Math.hypot(). The key insight is that for distance comparisons, you don’t need the actual distance—just something that preserves the ordering. Squared distance does exactly that.
Key takeaways:
- Skip sqrt when comparing distances—compare
dx² + dy² < radius²instead - Pre-calculate squared radii at initialization, not in hot loops
- This technique works in any dimension (2D, 3D, etc.)
- Keep using
Math.hypot()when you need actual distance values - The performance gain is 10-15x in hot paths
This is a fundamental game development optimization that transformed my struggling 30 FPS game into a smooth 60 FPS experience. The math is simple, the code is clean, and the performance gain is massive.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
- 👨💻 Reddit r/javascript - TIL about Math.hypot()
- 👨💻 MDN - Math.hypot()
- 👨💻 Game Programming Patterns
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments