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!