Javascript collision detection in tile based game (demo page available)

Started by
7 comments, last by hdnine 11 years, 5 months ago
The demo can be tested here (it also has a syntax highlighter)
http://www.wonderwor...y-and-friction/

Hey everyone,

I've yet again started a small game project where immediately i got stuck on the same subject as before, collision detection. I know that i'm not that good at math so i went with the approach i assumed as being correct. That is testing the player object against all tile objects on screen to see if there is a collision:

The syntax highlighter went mad on me so i pasted the code as text instead (it can however be viewed at the link above)

// If moving up
for(var index in Level.currentLayout) {
var obj = Level.currentLayout[index];

if(87 in Game.keys || Player.vel.y < 0 || Player.airborn) {
if(((Player.right >= obj.left && Player.right <= obj.right) || (Player.left <= obj.right && Player.left >= obj.left)) && (Player.top - distance >= obj.top && Player.top - distance <= obj.bottom)) {
Player.pos.y = obj.bottom + 1;
Player.collision.top = true;
break;
} else {
Player.collision.top = false;
}
}
}
// If moving left
for(var index in Level.currentLayout) {
var obj = Level.currentLayout[index];

if(65 in Game.keys || Player.vel.x < 0) {
if((Player.left - distance <= obj.right && Player.left - distance >= obj.left) && ((Player.bottom >= obj.top && Player.bottom <= obj.bottom) || (Player.top >= obj.top && Player.top <= obj.bottom))) {
Player.vel.x *= -1;
Player.collision.left = true;
break;
} else {
Player.collision.left = false;
}
}
}
// If moving down
for(var index in Level.currentLayout) {
var obj = Level.currentLayout[index];

if(((Player.right >= obj.left && Player.right <= obj.right) || (Player.left <= obj.right && Player.left >= obj.left)) && (Player.bottom + distance >= obj.top && Player.bottom + distance <= obj.bottom)) {
Player.pos.y = obj.top - Player.height - 1;
Player.collision.bottom = true;
Player.airborn = false;
break;
} else {
Player.collision.bottom = false;
Player.airborn = true;
}
}
// If moving right
for(var index in Level.currentLayout) {
var obj = Level.currentLayout[index];

if(68 in Game.keys || Player.vel.x > 0) {
if((Player.right + distance >= obj.left && Player.right + distance <= obj.right) && ((Player.bottom >= obj.top && Player.bottom <= obj.bottom) || (Player.top >= obj.top && Player.top <= obj.bottom))) {
Player.vel.x *= -1;
Player.collision.right = true;
break;
} else {
Player.collision.right = false;
}
}
}

It kinda works but i keep having this feeling that the code is just too complicated for a tile based 2D platform game, or, simply that it's badly written? Without physics it works really well but with it i get stuck on edges between tiles and on tiles. Alos, the gravity seems too slow but if i increase it, other things like the jumping starts to act up so i in turn have to increase that to compensate and all of a sudden everything gets messed up.

I have some code that generates the level tiles and displays them on canvas which works nicely. The problem is somewhere with the collision detection and since my math really suck, i have been reading and reading about different approaches and i just don't understand most of them.

I would really appreciate if someone could give me some input on a more correct way to handle this, preferably with example code or demo pages. Thanks a bunch!

Also: please add Javascript/Canvas to the Topic Prefix ^^
Advertisement
Do you have many objects? Collision detection algorithms usually have a cost that increase quadratically with number of objects. If so, consider using a quadtree.
[size=2]Current project: Ephenation.
[size=2]Sharing OpenGL experiences: http://ephenationopengl.blogspot.com/
To be honest, at the moment i'm really struggeling with the issue of having physics (gravity/friction/acceleration) work with collision detection. Since the project is primarely nothing more than trying to teach myself better game programming, the number of objects at the moment are few. The player, tiles and possibly some moving platforms as the next step.

It's really discouraging to sit four hours everyday to try and solve one simple problem so that i can proceed on to the next steps of the development. I've tried a few approaches but never got any of them to work... probably due to faulty implemenation. I'm not sure why this is so hard for me and that's why i was hoping to get som input. Believe me when i say that i have read a lot on the subject but there are so many approaches and uses for collision detection so it's hard to find the one that will work for you.

I have looked up quadtrees and will have to read more about it. Not sure if AABB is a collision detection teqhnique but i was looking at that too. Anyway, thanks!
On other thing, and maybe this is the wrong way to go about it. The coll detect is checking in advance for any tiles that it might collide with each frame, thus, the added value "distance" to the check which has the formula:

distance = Math.ceil(this.maxVel * delta);

Delta is the number of pixels the player needs to move each frame in order to keep the movement smooth, at least, this is how i think it works and is another of those issues that i'm not entirely sure about. I chose this approach because without a coll detect ahead of time, the player has to collide first and then move backwards instead of checking if there is a collision next frame and make the player stop at the edge of the tile. The first option tend to gice a quick but subtle flicker effect which i'm not to fond of.

To be honest, at the moment i'm really struggeling with the issue of having physics (gravity/friction/acceleration) work with collision detection.

It's really discouraging to sit four hours everyday to try and solve one simple problem so that i can proceed on to the next steps of the development.



Ha, yes. I have been trying to do a platformer for the last two-ish weeks, and like you I got quite frustrated because initially I thought that it wouldn't be so hard, or that it was a "newbie phase problem". However, in reality, I think it the problem is medium to hard. It is not a simple problem. Each domain (ie animation, collision detection, player control, state machines, etc) on its own is kind of trivial. Merging them all to make a jumping, walking, falling, animated player (that gets eaten by crocodiles but not doves) is kind of hard.

(And, the player class (which I suppose you started with) is presumably the hardest of all, since it can do the most.)

To be honest, I spent the first few days of coding not coding at all, but just staring at the screen absent mindedly, going through (and rejecting) various code scenarios in my head. Oftentimes, my head would implode a bit because it couldn't even fathom all the things to be considered at once.

Eh, so to summarize I'd like to say: It's a hard problem. There is no "clean", automagic solution that will accomplish what you want without if clauses. :)

(but it would be nice if someone would prove me wrong ofc... )
~ Not that I really have a clue
This code seems to be over complicated.

First you have 4 for loops within this code, that mean every time you add an object to the screen your adding 4 checks for collision.

I would recommend attempting to rewrite the code to something like the following.


var collisionDirection;
for(var index in Level.currentLayout){
if(CheckCollision(Player, Level.currentLayout[index]){ //<-- Check obj top bottom left right vs player top bottom left right
collisionDirection = getCollsionDirection(Player, Level.currentLayout[index]; //Get where we collided
Player.doCollisionAction(Level.currentLayout.type, collisionDirection); //Player function that defines what happens when you collide with said type.
}
}


This simplified the code and cleans it up. It also only runs through the objects once and find a collision. I would probably try two for loops to check for all collision and create a list of objects on screen and only check collision on those for further optimization.

Hope this helps.
Right, thanks... right now i'm not that worried about optimization, more that the collsion itself was faulty. But thanks anyway i will certainly take a look at it. ^^
There are 2 things I would do to straighten up the code.

#1, have a separate function to check for input, and apply velocities to the player there instead of checking for keys in the movement location. This will help both in movements and collision detection.

#2, If you have a list of objects your player can collide with, then, every frame, have him check that list and see if he's collided. Realize, for platformers, you'll need to check specifically for collisions along the X-axis (to stop the player moving horizontally, while he's still moving vertically), and and Y-axis (to bump his head, or just bump his feet, if you want them to pass through the bottom of platforms).

There are a few posts about this that I've replied too that has some good info (with pseudo code) that handles moving and jumping in a platformer. Please check them out Here and Here

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

Thanks! ^^

This topic is closed to new replies.

Advertisement