Reputation: 11
I have been looking around on forums and i haven't been able to find anything specific enough for what i am having trouble with. I am trying to make a function for collision detection in a 2D platformer, and at first i could make it work with explicitly naming every vertex and it where the player would then move to upon collision, but that was not efficient at all and ended up with alot of retyping things. It would work at first but over time it would become more of a hassle than it is worth. I am trying to make a collision detection function that will be able to tell me which side the player is colliding on and that will be able to move the character to the proper position. I am using allegro 5 and c++ and this is my function thus far:
bool Collision(int x1,int y1,int h1,int w1,int x2,int y2,int h2,int w2){
if(x1 < x2 + w2 &&
x2 < x1 + w1 &&
y1 < y2 + h2 &&
y2 < y1 + h1)
{return 1;}
return 0;
}
how could i make it so that upon collision my object will stop and not continue through the object? but also know that it has landed on top of something, or hit the side or bottom of it because those would each be different reactions.
Upvotes: 1
Views: 2108
Reputation: 25
If you are just trying to prevent player from going inside blocks in platformer. You could do the collision check in somewhere close to place you are doing the movement of the players. There you could check on each axis of movement and then redo that movement in case it was causing collision. This way it would be possible to slide on objects and prevent from going inside on blocks on specific axis. Ie. (Sorry about putting everything into classes. I don't know what kind of system you have exactly but I recommend using classes for abstraction.)
bool Collision(GameObject o1, GameObject o2){
return !(o1.x + o1.w < o2.x || o1.y + o1.h < o2.y || o1.x > o2.x + o2.w || o1.y > o2.y + o2.h);
}
void moveThisObject(GameObject &movingObject) {
bool redoMovement;
// Move and test x-axis movement caused collision.
movingObject.x += movingObject.speed.x;
redoMovement=false;
for (int t=t;t<objectsInGame;t++) {
if (Collision(movingObject,gameObj[t])
redoMovement=true;
}
if (redoMovement)
movingObject.x -= movingObject.speed.x;
// Move and test y-axis movement caused collision.
movingObject.y += movingObject.speed.y;
redoMovement=false;
for (int t=t;t<objectsInGame;t++) {
if (Collision(movingObject,gameObj[t])
redoMovement=true;
}
if (redoMovement)
movingObject.y -= movingObject.speed.y;
}
class GameObject {
public:
double x,y,w,h;
Vec2 speed;
}
class Vec2 {
public:
double x,y;
}
And for the question of function to check which side the object is hitting it could be done ie this way to replace those corresponding parts in the code:
// for x-axis testing
if (redoMovement) {
if (movingObject.speed.x>0) //moving object hit object2 from left to right
movingObject.x -= 1; // move back left
if (movingObject.speed.x<0) //moving object hit object2 from right to left
movingObject.x += 1; // move back right
}
// for y-axis testing
if (redoMovement) {
if (movingObject.speed.y>0) //moving object hit object2 from up to down
movingObject.y -= 1; // move back down
if (movingObject.speed.y<0) //moving object hit object2 from down to up
movingObject.y += 1; // move back up
}
There maybe some errors I didn't compile the code. If your movement is more than one pixel in speed it could then need some adjusting to make the objects really stick in the walls.
Upvotes: 1
Reputation: 7065
EDITED AGAIN If you want the object to stop JUST BEFORE actual colliding without sharing the same actual edge pixel, try this:
bool Collision(int x1,int y1,int h1,int w1,int x2,int y2,int h2,int w2){
if((x1 + w1) >= (x2 - 1) || // object 1 hitting left side of object 2
(x1 - 1) <= (x2 + w2) || // object 1 hitting right side of object 2
(y1 - 1) <= (y2 + h2) || // Object 1 hitting bottom of object 2 (assuming your y goes from top to bottom of screen)
(y1 + h1) >= (y2 - 1)) // Object 1 hitting top of object 2
return 1;
return 0;
}
OR
int Collision(int x1,int y1,int h1,int w1,int x2,int y2,int h2,int w2){
if((x1 + w1) >= (x2 - 1)) return 1; // object 1 hitting left side of object 2
if((x1 - 1) <= (x2 + w2)) return 2; // object 1 hitting right side of object 2
if((y1 - 1) <= (y2 + h2)) return 3; // Object 1 hitting bottom of object 2 (assuming your y goes from top to bottom of screen)
if((y1 + h1) >= (y2 - 1)) return 4; // Object 1 hitting top of object 2
return 0; // no collision
}
This way they should never actually share the same pixel.
ORIGINAL I think that where you want to go with this is more like:
bool Collision(int x1,int y1,int h1,int w1,int x2,int y2,int h2,int w2){
if((x1 + w1) >= x2 || // object 1 hitting left side of object 2
x1 <= (x2 + w2) || // object 1 hitting right side of object 2
y1 <= (y2 + h2) || // Object 1 hitting bottom of object 2 (assuming your y goes from top to bottom of screen)
(y1 + h1) >= y2) // Object 1 hitting top of object 2
return 1;
return 0;
}
This answer assumes that you wish to know when they two object intact OCCUPY the same coordinate edge (i.e. the less-than / greater-than or equal versus without the equal)
This answer does not however return WHICH EDGE is the interacting edge. If you wanted that, then you might do something more along these lines.
int Collision(int x1,int y1,int h1,int w1,int x2,int y2,int h2,int w2){
if((x1 + w1) >= x2) return 1; // object 1 hitting left side of object 2
if(x1 <= (x2 + w2)) return 2; // object 1 hitting right side of object 2
if(y1 <= (y2 + h2)) return 3; // Object 1 hitting bottom of object 2 (assuming your y goes from top to bottom of screen)
if((y1 + h1) >= y2) return 4; // Object 1 hitting top of object 2
return 0; // no collision
}
Now on the outside you just have to decode your edge detection cases of 1 - 4.
Upvotes: 1