Public Group

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

## 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 on other sites
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 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

1. 1
2. 2
3. 3
Rutin
13
4. 4
5. 5

• 20
• 10
• 9
• 9
• 11
• ### Forum Statistics

• Total Topics
633694
• Total Posts
3013365
×