Sign in to follow this  
settis

2D Collision function

Recommended Posts

Well I am about to make a collision detection for a tile-map. Hmm ... my problem is not how to do it - logically my code should work - but as you can guess it doesn`t quite do what I want. (well I know that there are better ways to do a collision detection, and I know that I should not check all the tiles at once, but only those which are near to the player but i wanted to do something easy at first - and improve the code step by step) posx and posz, is the current position of the player and the for-loops go through all the tiles of my 2D-array and check it is walkable or not. If it is not woalkable the code checks if the player is within that tile. now my problem is that my function work just fine with the first 2 rows of my 2d array, after that it doesn`t recognize the not walkable tiles. does anyone see my error? how could it be possible that the function works for two rwos and ignores the rest? 2D map: 2 and 0 = walkable 1 = not walkable
int WorldMap1[20][20] = {                                          //15
                         {2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                         {2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1},
                         {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0},
                         {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
                         {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
                         {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
                         {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
                         {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
                         {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
                         {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
                         {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
                         {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
                         {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
                         {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
                         {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
                         {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, //16
                         {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
                         {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0},
                         {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0},
                         {2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};

Collision function:

int CollisionTile(float posx, float posz){
     int walk;
     
     for (int r=0; r<20; r++ ){
         for (int t=0; t<20; t++){
                  
             float coordx_a = 40 * r + 40;
             float coordx_b = 40 * r;         
             float coordz_a = 40 * t + 40;
             float coordz_b = 40 * t;
             
             float pos_posx = posx;
             float pos_posz = posz; 
             
                 if (WorldMap1[r][t] == 1){
                            if(pos_posx < coordx_a && pos_posx > coordx_b){
                               if (pos_posz < coordz_a && pos_posz > coordz_b){
                                 walk=0;
                                 return (walk);
                                 }
                            }   
                            else{
                                 walk=1;
                                 return (walk);
                            }
                 }                     
         }
     } 
     
     
}


Share this post


Link to post
Share on other sites
It looks like this has become conceptually very complicated. It doesn't need to be this much code, I think - as you trim it down, you would eventually hit a point where you'd just have to rewrite the function, anyway.

Secondly, there are some strange variable names that make understanding the code a bit of a chore. For instance, normally 2D arrays have an X and a Y coordinate, but you have an X and a Z coordinate system...?

My suggestion would be to dramatically rethink the function - might I recommend something along the lines of a function like this?


//returns true if the new position is walkable
bool IsNewPositionWalkable(int newX, int newY)
{
switch(WorldMap1[newX][newY])
{
case 0:
return true;
break;
case 1:
return false;
break;
case 2:
return true;
break;
default:
return true;
break;
}
}


To use this function, any time the player moves, you would call this function with the "new" location (the location he would be at after moving, assuming he was permitted). If it returns true, then it is walkable and he may then relocate to the new position. If false, then he collided with an unwalkable tile and he can't relocate to the new position.

Share this post


Link to post
Share on other sites
@settis: Use a debugger to find out what actually happens when you run your game. It's usefull for tracking down logical errors like this.

Anyway, let's tackle this problem step by step.
- First, you'll want to know which tiles the player collides with. You'll need the player position and it's height and width for that, as well as the tilemap data of course.
- Second, you'll check if any of those tiles is solid, unwalkable. That should be easy with the function BTownTKD provided.
- Third, if the player collides with an unwalkable tile, you'll probably want to push him out of it - stopping movement would result in a player getting stuck, after all. That, or you want to prevent the player from ever ending up in an unwalkable tile. There are multiple options there, so you'll have to decide what behaviour you really want, as this will affect your programs design.


@BTownTKD: As I said above, your function certainly simplifies things a bit, but it doesn't solve the whole problem.

Anyway, if we're talking about shorter code, the following code does exactly the same. There's no need for a switch case here if you're only returning false on one occasion. Actually, if there's a lot of different tile types, it's probably better to store that data in an array or std::vector, and simply look it up.
//returns true if the new position is walkable
bool IsNewPositionWalkable(int newX, int newY)
{
return (WorldMap1[newX][newY] != 1);
}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this