Monday, March 7, 2016

javascript - Roguelike 2D Collision Detection


I'm just a normal guy trying to do some basic collision detection but I suck at it. I either get stuck in a wall or I go in reverse in the wrong direction trying to update the player position to a non collision part. So here is how I check for collision and this function will return true or false. True if collision and false if not.


roguelike.player.collision = function() {
var player = roguelike.player;
for(var i = 0; i < roguelike.map.rooms.length; i++) {
var room = roguelike.map.rooms[i];
if(player.x > room.x && player.x < room.x + room.width && player.y > room.y && player.y < room.y + room.height){
return false;
}

}
return true;
};

This function works just fine just like expected. But it's when I try to stop the player when he hits a wall is where I get bugs. When the player goes down and hits a wall he gets stuck there. Here is the function that updates the player position.


roguelike.update = function() {
var player = roguelike.player;

//Left
if(player.moving.left && !player.collision()) {

player.x -= roguelike.game.speedPerSecond(player.speed);
} else if(player.collision()){
player.resetPosition();
}
//Up
if(player.moving.up && !player.collision()) {
player.y -= roguelike.game.speedPerSecond(player.speed);
} else if(player.collision()){
player.resetPosition();
}

//Right
if(player.moving.right && !player.collision()) {
player.x += roguelike.game.speedPerSecond(player.speed);
} else if(player.collision()){
player.resetPosition();
}
//down
if(player.moving.down && !player.collision()) {

player.y += roguelike.game.speedPerSecond(player.speed);

} else if(player.collision()){
player.resetPosition();
}
player.savePosition();

};

So what I do is check what direction the player is moving and if there is no collision detected then the player is free to move. Otherwise if there is a collision I put the player position as the last position he was when there was no collision so he will be free to move. This works going left, up, and right, but not going down. Going down the player gets stuck in the collision and the resetPosition function doesn't put the player back in the safe zone.


So I know there must be a better way. And I would appreciate your advice on what you think that way should be.



Answer




Instead of testing the collisions ON the player, you should testing them AHEAD, to check whether there's a wall where the player WILL be walking. To do that, you'll only need to change 2 things:


1- Your player.collision function should accept two arguments: an x and y offset. You should add them to your collision checking algoythm too.


2- When calling player.collision, you should pass the offset equal to the movement the player would make.


In your code, this resumes as this:


roguelike.player.collision = function(x, y) { // The function now accepts 2 arguments
var player = roguelike.player;
for(var i = 0; i < roguelike.map.rooms.length; i++) {
var room = roguelike.map.rooms[i];
if(player.x + x > room.x && player.x + x < room.x + room.width
&& player.y + y > room.y && player.y + y < room.y + room.height)

{ // The offset is added to the player position when testing
return false;
}
}
return true;
};

And calling a movement would look like this:


if(player.moving.left
&& !player.collision(-roguelike.game.speedPerSecond(player.speed), 0) {

player.x -= roguelike.game.speedPerSecond(player.speed);
} else if(player.collision()){
player.resetPosition();
}

No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...