Jump to content
  • Advertisement
Sign in to follow this  
pathofwind

Collision Detection for surround walls. Please help!

This topic is 2568 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all, can someone please teach me how do I detect collision of surrounding walls correctly....Or lead me to a good tutorial for it..

This is my first time coding a game. I am trying to code a bomberman clone, but I am having problems with handling collisions between bomberman and walls.
I was just following my intuition and it is just really hard to figure out by myself. I have debugged for the whole night already...

Here's my problem,
Even though my bomberman cannot move move diagonally,
but this is allowed,

OOWW
BBWW
BBOO
OOOO

BBBB: A Bomberman, WWWW: A Wall block O: free space

Currently, my bomberman detects the box right beside him really well. However, it fails when handling walls that are diagonal to him.

I use a bounding-box collision detection method and here is part of my code.



#define COLLISION_LEFT 1 // 0001
#define COLLISION_RIGHT 2 // 0010
#define COLLISION_UP 4 // 0100
#define COLLISION_DOWN 8 // 1000

.....
/*
* Display loop
*/
void display(void) {
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glLineWidth(1.3);
glColor3f (1.0, 1.0, 1.0);


// Draw the Map
for (int i=0; i<num_grids_x; i++) {
for (int j=0; j<num_grids_y; j++) {
blocks[j]->draw();
}
}

// Collision Detection
double x = player->getLocationX();
double y = player->getLocationY();

int x_right = roundNum(x+GRID_SIZE)/GRID_SIZE;
int x_mid = roundNum(x)/GRID_SIZE;
int x_left = roundNum(x-GRID_SIZE)/GRID_SIZE;

int y_top = roundNum(y+GRID_SIZE)/GRID_SIZE;
int y_mid = roundNum(y)/GRID_SIZE;
int y_bot = roundNum(y-GRID_SIZE)/GRID_SIZE;


// boundary conditions
if (y_top > 19) y_top = 19;
if (y_bot < 0) y_bot = 0;
if (x_right > 19) x_right = 19;
if (x_left < 0) x_left = 0;

if (y_mid > 19) y_mid = 19;
if (y_mid < 0) y_mid = 0;
if (x_mid > 19) x_mid = 19;
if (x_mid < 0) x_mid = 0;

// Check top left block
if (blocks[y_top][x_left]->getGrid() != SPACE) {
if (player->collideWith(blocks[y_top][x_left])) {
collision |= 5;
}
}

// Check top right block
if (blocks[y_top][x_right]->getGrid() != SPACE) {
if (player->collideWith(blocks[y_top][x_right])) {
collision |= 6;
}
}


// Check bottom left block
if (blocks[y_bot][x_left]->getGrid() != SPACE) {
if (player->collideWith(blocks[y_bot][x_left])) {
collision |= 9;
}
}

// Check bottom right block
if (blocks[y_bot][x_right]->getGrid() != SPACE) {
if (player->collideWith(blocks[y_bot][x_right])) {
collision |= 10;
}
}

// Check left block
if (blocks[y_mid][x_left]->getGrid() != SPACE) {
if (player->collideWith(blocks[y_mid][x_left])) {
collision |= 1;
}
} else {
collision &= 14;
}
// Check right block
if (blocks[y_mid][x_right]->getGrid() != SPACE) {
if (player->collideWith(blocks[y_mid][x_right])) {
collision |= 2;
}
} else {
collision &= 13;
}

// Check top block
if (blocks[y_top][x_mid]->getGrid() != SPACE) {
if (player->collideWith(blocks[y_top][x_mid])) {
collision |= 4;
}
} else {
collision &= 11;
}

// Check bottom block
if (blocks[y_bot][x_mid]->getGrid() != SPACE) {
if (player->collideWith(blocks[y_bot][x_mid])) {
collision |= 8;
}
} else {
collision &= 7;
}

// if collision was detected, forbid the movement in that direction
if (collision) {
switch (player_dir) {
case 1: if ((collision&1) != COLLISION_LEFT) player->updateLocationX(-0.1); break;
case 2: if ((collision&2) != COLLISION_RIGHT) player->updateLocationX(0.1); break;
case 4: if ((collision&4) != COLLISION_UP) player->updateLocationY(0.1); break;
case 8: if ((collision&8) != COLLISION_DOWN) player->updateLocationY(-0.1); break;
}
}
else {

switch (player_dir) {
case 1: player->updateLocationX(-0.1); break;
case 2: player->updateLocationX(0.1); break;
case 4: player->updateLocationY(0.1); break;
case 8: player->updateLocationY(-0.1); break;
}
}
player->draw();
glFlush();
glutSwapBuffers();

}


void processSpecialKeys(int key, int x, int y) {
switch(key) {
case GLUT_KEY_LEFT: player_dir = 1; break;
case GLUT_KEY_RIGHT: player_dir = 2; break;
case GLUT_KEY_UP: player_dir = 4; break;
case GLUT_KEY_DOWN: player_dir = 8; break;

}
}

void processSpecialKeysUp(int key, int x, int y) {
switch(key) {
case GLUT_KEY_LEFT: player_dir &= 14; break;
case GLUT_KEY_RIGHT: player_dir &= 13; break;
case GLUT_KEY_UP: player_dir &= 11; break;
case GLUT_KEY_DOWN: player_dir &= 7; break;

}
}





bool Object::collideWith(Object *rhs) {
return Object::collideWith(rhs->x, rhs->y);
}

// bounding-box collision detection
bool Object::collideWith(double x2, double y2) {
double x1 = this->x;
double y1 = this->y;

if(x1 + GRID_SIZE > x2)
{
if(x1 < x2 + GRID_SIZE)
{
if(y1 + GRID_SIZE > y2)
{
if(y1 < y2 + GRID_SIZE)
{
return true;
}
}
}
}
return false;
}

void Object::updateLocationX(double x_diff) { x += x_diff; }

void Object::updateLocationY(double y_diff) { y += y_diff; }


Sorry, my code is really messy. It's just for reference if anyone is interested...

I think the problem with my attempt is that because I hand the checks of the diagonal blocks first.
I've also tried something like

//check left
//check top left
//check bottom left
//if any collides then turn left collision on : collision |= 1
//if no collides then turn left collision off : collision &= 14

//and do it for the other three directions

However, with that approach, my bomberman cant even move properly.


I am wondering if there is a convention of coding these type of collision and if there is any good article about it can you kindly lead me to it?
Thanks!

Share this post


Link to post
Share on other sites
Advertisement
The approach I always take for tilebased collision detection is as follows:


for every tile which is near to bomberman
if( bombermans x position is less than the tile x position + width / 2 and bombermans x position is greater than the tile x position - width / 2)
{
if( bombermans y position is less than the tile y position + width / 2 and bombermans y position is greater than the tile y position - width / 2)
{
return true; //a collision has happened
}
}

return false;


Then call that every time a direction key is pressed to allow or deny bomberman's movement.

but I really am a novice gamedev, so there are probably better ways!

Good luck!
Lolliver.

Share this post


Link to post
Share on other sites
Why does it not collide?
Let's see. I don't know where you declare [font="Courier New"]collision[/font], but I'd take for granted it starts being 0. Let's say you hit top-left so [font="Courier New"]collision |= 5[/font] (in this context that is [font="Courier New"]collision = 5[/font]).
Now, [font="Courier New"]collision [/font]is true so the [font="Courier New"]switch [/font]fires its comparison... but this will always fail as you have used bitmasks. It can only match pure directions (up, down, left, right) as those are single-bit masks, furthermore, your logic actually clears diagonals (see below).
In short, you seem to have not understood what [font="Courier New"]switch [/font]is supposed to do.

Suppose we hit top-left (only) --> [font="Courier New"]collision == 5[/font]. 5dec == 0x05 == 0101
Then you test left, right top, bottom. All those tests fail because of assumption.
[source]
0101 &
1110 & //14
1101 & //13
1011 & // 11
0111 --> 0000 // 7

Final result: always 0
[/source]


Anyway.Perhaps it's just me but I think that's fairly backwards.
Basically what you're doing is to see if {box can move 12346789}.
I'd rather do something else. Start from the current position {5} and add the movement vector assuming it succeeds. You obtain a new bounding box at {5+M}. Intersect this new box with the map. If it fails, reject the movement (direction is irrelevant). If it is accepted, go to a transitional "moving" state. Run cell transition animation and go back to standard testing as soon as it's done.

EDIT: engrish, small clarification on numbers involved. Edited by Krohm

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!