Search code examples
javascripthtmlcanvascollision-detection

Collision detection in HTML5 canvas. Optimization too


I am making a platform game, but i have a problem with my collision detection. I've made a function that draws a tile on the screen/map. In that function is my collision detection, it works fine when only one tile is drawn, but when i created "stairs" with three tiles, the first tile doesnt work propertly. The player is just being "pushed" up on the tile. The side detection isn't working. And the other tiles are working just fine.

Here is the code for collision detection and tile drawing:

//Function that allows you to draw a tile
function drawTile(type, x, y, collision){
    var tileImg = new Image();
    tileImg.onload = function(){
        ctx.drawImage(tileImg, x, y)
    };
    tileImg.src = "images/" + type + ".png";

    if (collision){
        //Worst collision detection ever.
        if((player_x + player_width == x) && (player_y + player_height > y)){
            canMoveRight = false;
        }else if((player_x == x + 32) && (player_y + player_height > y)){
            canMoveLeft = false;
        }else if((player_y + player_height > y) && (player_x + player_width >= x) && (player_x + player_width <= x + 64)){
            player_y = y - player_height;
        }else{
            canMoveRight = true;
            canMoveLeft = true;
        }
    }
}

//Draw the map
function drawMap(){
    drawTile("block", 96, 208, true);
    drawTile("block", 128, 208, true);
    drawTile("block", 128, 176, true);
};

As you can see, the collision detection code kinda sucks. So it also would be good if you showed me better ways of making it.

Just say if you need to know something. :)


Solution

  • With box collision detection, it's important to compare the x and y separately. Here's the pseudo code for how I've done something similar the past:

    var o1 = {x:100, y:229, w:30, h:30};
    var o2 = {x:100, y:200, w:30, h:30};
    
    //Amount of overlap
    leftDist    = (o2.x - o2.w/2) - (o1.x + o1.w/2);
    rightDist   = (o1.x - o1.w/2) - (o2.x + o2.w/2);
    topDist     = (o2.y - o2.h/2) - (o1.y + o1.h/2);
    bottomDist  = (o1.y - o1.h/2) - (o2.y + o2.h/2);
    
    
    if( leftDist    < 0 &&
        rightDist   < 0 &&
        topDist     < 0 &&
        bottomDist  < 0 ){
    
        //Get the closest collision
        var closest;
        var direction; //0 = left, 1 = right, 2 = top, 3 = bottom
    
    
        var xDist = o1.x - o2.x;
        var yDist = o1.y - o2.y;
    
        if(xDist < 0) {
            closest = leftDist;
            direction = 0;
        } else {
            closest = rightDist;
            direction = 1;
        }
    
    
        if(yDist < 0) {
            if(closest < yDist) {
                closest = topDist;
                direction = 2;
            }
        } else {
            if(closest < yDist) {
                closest = bottomDist;
                direction = 3;
            }
        }
    
    
    
        //Last, jump to the contact position
        switch(direction) {
    
            case 0:
                o1.x += closest;
                break;
            case 1:
                o1.x -= closest;
                break;
            case 2:
                o1.y += closest;
                break;
            case 3:
                o1.y -= closest;
                break;
    
        }
    
    
    }
    

    Let me know if you have any questions about it.