Search code examples
javascriptcollision-detectionthree.js

Three.js detect collision between 2 moving objects using a Ray


I'm making a breakout game in 3D using THREE.js and the WebGL render. I want to use THREE.Ray to detect collision between the bouncing ball and the platform at the bottom which can be controlled by you, but I'm having trouble.

I've managed to cast a ray from the platform to the ball (or other way around) but once I do that, the ball gets stuck in the middle of the screen and cannot be animated.

var ray = new THREE.Ray( platform.position, ball.position.subSelf( platform.position ).normalize() );
var intersects = ray.intersectObject( ball );

if ( intersects.length > 0 ) console.log(intersects[0].distance);

I've tried removing the subSelf and normalize() but that breaks the detection.

Here is the game and code can be found in script.js:

http://dl.dropbox.com/u/4531743/WebGL/Breakout-3D/index.html

If you open the console, you can see that the distance value changes if you move the panel, so that's good. But the ball cannot be animated because at every frame it's being set to that position.

http://dl.dropbox.com/u/4531743/WebGL/Breakout-3D/index.html#disableRay

Above is how I originally did it, just by calculating the Z position of the ball and panel and seeing if it's bigger and is inside the panel's width (x) coordinates, and if it is, bouncing it off.

The ball's bouncing is just changing the X and Z coordinates by a fixed amount every frame, and if it goes too far in either direction, reversing that amount so it goes back.


Solution

  • After some playing around I worked it out.

    var ray = new THREE.Ray( ball.position, new THREE.Vector3(ball.position.x, ball.position.y, platform.position.z).subSelf( ball.position ).normalize() );
    
    var intersects = ray.intersectObject( platform );
    
    if ( intersects.length > 0 ) {
    
        var face = intersects[0].face.d,
        dist = intersects[0].distance;
    
        if(face == 4 && dist <= 7) sizes.ball.velocityZ = -sizes.ball.velocityZ;
    
    };
    

    Basically, that way I'm always projecting a ray straight down from the ball, and if the platform is directly below it and the distance to the platform is close enough, I reverse the direction of the ball.