Reputation: 26611
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
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