I am trying to implement my own collision detection for a 2.5d voxel style platformer using Three.js. I have a problem with my implementation - if the framerate is too low or the character is moving too fast (usually when falling from high places) it falls right through. Is there a way to improve collision detection to be immune to problems like this?

This is how I detect collisions:

function render(){
    requestAnimationFrame(render);

    setVelocity();
    animate();
    manageCollisions();

    renderer.render(scene, camera);

}

function manageCollisions(){
//Check every game object for collision -> TODO: implement broad phase when dealing with many objects
for(i=0; i < world.length; i++){

    //Check for bottom collision <- ALWAYS check (unless moving up)
     if(velocityY<0) {
        if( (character.position.y - character.height/2) < (world[i].position.y + world[i].height/2)
            && (character.position.y + character.height/2) > (world[i].position.y + world[i].height/2)
            && (character.position.x + character.width/2) > (world[i].position.x - world[i].width/2)
            && (character.position.x - character.width/2) < (world[i].position.x + world[i].width/2))
        {
            console.log("bottom collision " + i);

            velocityY=0;
            jumped=false;
            grounded = true;

            character.position.y = world[i].position.y + world[i].height/2 + character.height/2 - 0.1; //-0.1 prevents shaking
        } else { 
            grounded = false;
        }

    }

    //Check for right collision <- ONLY if moving right (velocityX is positive)
    if(velocityX > 0){ 
        if( (character.position.y) < (world[i].position.y + world[i].height/2)
            && (character.position.y + character.height/2) > (world[i].position.y - world[i].height/2)
            && (character.position.x + character.width/2) > (world[i].position.x - world[i].width/2)
            && (character.position.x - character.width/2) < (world[i].position.x - world[i].width/2))
        {
            console.log("right collision" + i);
            velocityX=0;
            character.position.x = world[i].position.x - world[i].width/2 - character.width/2;
        }
    }

    //check for left collision <- ONLY if moving left (velocityX is negative)
    if(velocityX < 0){ 
        if( (character.position.y) < (world[i].position.y + world[i].height/2)
            && (character.position.y + character.height/2) > (world[i].position.y - world[i].height/2)
            && (character.position.x - character.width/2) < (world[i].position.x + world[i].width/2)
            && (character.position.x + character.width/2) > (world[i].position.x + world[i].width/2))
        {
            console.log("left collision" + i);
            velocityX=0;
            character.position.x = world[i].position.x + world[i].width/2 + character.width/2;
        }
    }

    //check for top collision <- ONLY if moving up (velocityY is positive)
    if(velocityY > 0){
        if( (character.position.y + character.height/2) > (world[i].position.y - world[i].height/2)
            && (character.position.y - character.height/2) < (world[i].position.y - world[i].height/2)
            && (character.position.x + character.width/2) > (world[i].position.x - world[i].width/2)
            && (character.position.x - character.width/2) < (world[i].position.x + world[i].width/2))
        {
            console.log("top collision" + i);
            velocityY=0;
            character.position.y = world[i].position.y - world[i].height/2 - character.height/2;
        }
    }



}

}

marked as duplicate by MichaelHouse Nov 26 '14 at 16:41

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • It would be easier to read an overview of the general method rather than the specific code you're using. (The question sounds like your issue is conceptual, not technical.) – Anko Nov 26 '14 at 12:47
  • @Anko I'm moving the character with x and y-axis velocities and on every frame I test for collisions with all world objects (I'll implement broad phase later - the problem is still here even with only 2 objects in world). If collision is detected the corresponding velocity is set to 0 and the position is adjusted so that the character doesn't penetrate any objects. The problem is that if the object is falling too fast it moves from above the object to below the object in one frame and therefore no collision is detected. – Tilen Pogačnik Nov 26 '14 at 13:33
up vote 1 down vote accepted

Overview

Essentially I think your talking about the problem where objects move to far in a single update step thus allowing them to seemingly pass through walls. This is a common problem, but an understandably irritating one for the player - although sometimes it's fun.

Direct Solution

The most direct way of answering your question I can think of is to somehow specialise your collision detection/physics simulation to detect collisions for the entire space occupied by the shape over the last frame.

This sounds complicated because it is.

Essentially, you need to first be able to define a better path of traversal for your object. If you're using something like an euler interator for position then the movement is a straight line per-frame. This is probably not accurate enough since you missed a few frames, so you need another method to calculate the actual path taken by the object over the last frame.

Once you have this, you need to take the bounding shape used in collision detection and extrude it along this path, resulting in a new shape which encompasses all space occupied by the object over the last frame.

Then detect collisions with this, work out the new path of the object post collision and repeat until the object's movement has been simulated for a long enough period.

This solution, while accurate, is probably impractical, prone to failure, hard to write and will probably be such a drain on resources that it will cause more slowdown than before.

Easy Solution

The easiest way is to fix your timestep. The linked article discusses a way to setup your game-loop such that you always get your updates in fixed timesteps while rendering frames at the highest rate possible on the current machine.

With a fixed timestep you are somewhat immune to the effects of framerate drops. If a frame takes longer, you get more update steps. It isn't immune to objects moving to fast, but that can be fixed by capping the maximum speed of some objects or using smaller time steps.

Not the answer you're looking for? Browse other questions tagged or ask your own question.