Joey Morani
Joey Morani

Reputation: 26611

Using THREE.Raycaster to detect collisions

I've created this function which is called in my render loop to detect collisions and move the player/camera (it's a first-person game) The collisions are detected using a CubeGeometry named pCube which is moved to match the camera every frame:

// Player movements
function pMovements() {
    mPlayer.colBottom = false;

    pCube.position.x = mPlayer.yawObject.position.x + 50; // The cube is placed +50 so we can see/debug it.
    pCube.position.y = mPlayer.yawObject.position.y - 10;
    pCube.position.z = mPlayer.yawObject.position.z;

    // -- COLLISION DETECTION START --
    var originPoint = pCube.position.clone();

    for (var vertexIndex = 0; vertexIndex < pCube.geometry.vertices.length; vertexIndex++)
    {       
        var localVertex = pCube.geometry.vertices[vertexIndex].clone();
        var globalVertex = localVertex.applyMatrix4( pCube.matrix );
        var directionVector = globalVertex.sub( pCube.position );

        var ray = new THREE.Raycaster( originPoint, directionVector.clone().normalize() );
        var collisionResults = ray.intersectObjects( collidableMeshList );
        if ( collisionResults.length > 0 && collisionResults[0].distance < directionVector.length() ) {

            // Bottom vertices
            if (vertexIndex == 2 || vertexIndex == 3 || vertexIndex == 6 || vertexIndex == 7) {
                mPlayer.colBottom = true;
                mPlayer.velocity.y = Math.max( 0, mPlayer.velocity.y ); // Stop falling
            }
        }
    }
    // -- COLLISION DETECTION END --

    var delta = (Date.now() - time) * 0.1;

    mPlayer.velocity.x += (-mPlayer.velocity.x) * 0.08 * delta; // walking
    mPlayer.velocity.z += (-mPlayer.velocity.z) * 0.08 * delta; // walking
    if (mPlayer.colBottom == false) {
        mPlayer.velocity.y -= 0.1 * delta; // falling
    }

    if (mPlayer.moveForward) mPlayer.velocity.z -= mPlayer.speed * delta;
    if (mPlayer.moveBack) mPlayer.velocity.z += mPlayer.speed * delta;
    if (mPlayer.moveLeft) mPlayer.velocity.x -= mPlayer.speed * delta;
    if (mPlayer.moveRight) mPlayer.velocity.x += mPlayer.speed * delta;

    mPlayer.yawObject.translateX(mPlayer.velocity.x);
    mPlayer.yawObject.translateY(mPlayer.velocity.y); 
    mPlayer.yawObject.translateZ(mPlayer.velocity.z);

    if (mPlayer.yawObject.position.y < -2000) {
        // Player has fallen out of bounds :( so re-initialise the players position
        mPlayer.velocity.y = 0;
        mPlayer.yawObject.position.y = 100;
        mPlayer.yawObject.position.x = 0;
        mPlayer.yawObject.position.z = 0;

        mPlayer.yawObject.rotation.y = 0;
        mPlayer.pitchObject.rotation.x = 0;
    }

    if (mPlayer.moveDown) {
        mPlayer.yawObject.position.y -= 1;
    }
    if (mPlayer.moveUp) {
        mPlayer.yawObject.position.y += 1;
    }
}

Click here for the demo.
WASD to move. Space to jump (sort of). The black cube/rectangle mirrors the cameras position +50 on the x-axis. Collisions are detected on the cube.

Basically I have two questions about this. Should I be using the vertices of the cube to detect collisions, or the faces? If an object was smaller than the cube, no collision would be detected because it wouldn't hit any vertices. So should I rewrite it for the faces instead?

Secondly, how can I prevent the cube falling too far down when a collision is detected. If you check the demo, whenever the cube falls off something it will keep falling for a while before stopping. I assume has something to do with mPlayer.velocity.y but I haven't been able to fix it. Even jumping makes the cube sink to far down into the floor.

Upvotes: 0

Views: 1564

Answers (1)

Stemkoski
Stemkoski

Reputation: 9045

To increase the "resolution" of your collision detection, you could add more vertices to the cube, e.g. when you declare pCube try:

pCube = new THREE.CubeGeometry(100,100,100, 5,5,5);

and the rest of your code could remain unchanged.

With regards to smaller objects "slipping between" the rays created for collision detection, in general if you use this method but have the small object create the rays, then you will detect collisions more accurately.

Upvotes: 1

Related Questions