Ok I'm making a top down style game that uses smooth scrolling that goes 2 pixels per frame. The issue is that the collision doesn't work well. If I put the character on a single tile surrounded by walls he can still wiggle around inside or if he goes around an edge it'll often cut the corner and wind up in the wall. I can't figure out how to fix this no matter what I try.
Movement code
Drawing code
//draw levelCurrent chunk al_set_target_bitmap(buffer); for(b=-1;b<21;b++){ for(c=-1;c<21;c++){ if(b*32-y>=0&& b*32-y<=640&& c*32-x>=0&& c*32-x<=640&& levelCurrent[c+levelx][b+levely]==1){ al_draw_bitmap(wall,(c*32)-x,(b*32)-y+32,0); } } }
Any help would be greatly appreciated. Thanks
I'm having a hard time understanding what your current movement code is doing. You have your levelCurrent array with both levelx and levely, but there doesn't appear to be any indication of what it does.
You can usually do one of two things:
1) Move your character. See if the character now collides with something; push the character back to the point where it no longer collides
2) Check before the character attempts to move whether something is in the way; go UP TO it, but don't allow it to go INTO it
I've always stored things like walls, other characters, etc. as individual objects, and then just iterate over those objects to see when things are trying to collide.
struct Object { unsigned int x, y; unsigned int width, height; // ... };
Create your objects (your walls, your characters, etc.) off of something like this. Then, when you try to move onto it, you test it like this:
for (i = 0; i < number_of_objects_on_screen; ++i) { if (is_collision(my_player, the_object[i], direction_my_player_is_moving) == true) // Handle what should happen when it collides, like preventing it from moving }
Create a rectangle class. Give your player and your walls a rectangle object. When you do collision, check whether the future player rectangle overlaps the wall rectangles for each wall that your player could be near.
Separate actions/input from movement/physics; and separate level coordinates from screen coordinates. Make functions/structs/classes that do that for you.
Huh I never actually thought of doing the collision checking separate from the movement. Thanks for your help.
No, checking collision as a prerequisite to movement is fine. Many people do the collision check after the movement has taken place, and then they see they can't determine how to move the character back into non-collision place.
About your code, there's certainly an issue with the mix of [levelx+10][levely+10], [levelx+11][levely+10]. What are 10 and 11 ?
In any case, it would be simpler to have x the complete coordinate in pixels, ie: x + levelx*32
This way, the tests look like:
edit Wait, I noticed my version is too simplified for full x and y freedom of movement. As long as the character is smaller than one tile, you can use checks:
if(key[KEY_UP]) { // Check the 2 pixels that are above the character's top angles if(levelCurrent[x/32][(y-2)/32]==1 && levelCurrent[(x+(character_width-1))/32][(y-2)/32]==1) y-=2; } if(key[KEY_DOWN]) { // Check the 2 pixels that are below the character's bottom angles if(levelCurrent[x/32][(y+(character_height-1)+2)/32]==1 && levelCurrent[(x+(character_width-1))/32][(y+(character_height-1)+2)/32]==1) y+=2; }
...
</code>
I'm just gonna post here again since I'm having issues with scrolling still.
Ok so I tried your collision code just on moving up to make sure it would work and it does but only after I've moved completely off the array map. The code doesn't seem to notice that any of the tiles are walkable until you move far enough out.
2nd issue is now whenever I move once I'm fully on a tile I'll jump to the next tile and then I can move normally till I pass another tile. It's kinda hard to explain but it basically looks like I'm jumping a tile everytime the array shifts.
I'll post the new code cause I've changed some things:
Movement Code:
Drawing Code:
//draw levelCurrent chunk for(b=0;b<20;b++){ for(c=0;c<20;c++){ if(b+(y/32)<21&& b+(y/32)>-1&& c+(x/32)<21&& c+(x/32)>-1&& levelCurrent[c+(x/32)][b+(y/32)].walkable==1){ al_draw_bitmap(wall,(c*32)-x,(b*32)-y+32,0); } } }
I don't see where your player gets drawn. (Or is it fixed in the center or something?) Am I right to assume the dimensions of your character are also 32x32?
Walkable = wall?
(x+(32-1))/32
What does this do... in the code for y directional collision?
Where are all your other collision checks?
Doesn't the rest of your code touch any of the variables presented here?
Are you familiar with the "%" (modulus) operator?
I'd like to see these variables in there: player_tile_pos_x, player_tile_pos_y, player_size_x, player_size_y, tile_size_x, tile_size_y.(Not necessarily named this way.)
Character gets drawn at the center at 320,352. Yes all my sprites so far are 32x32.
Looking at the (x+(32-1))/32 Im not entirely sure what thats use is. It was given to me above and I just used it.
I havent added any other collision checks yet because I wanted to make sure one worked first.
No the x and y variables are only used here.
Yea I just didn't think it would be useful here.
Here's everything I've got so far:
(The size limit wouldn't let me post it all so I added an attachement)
Looking at the (x+(32-1))/32 Im not entirely sure what thats use is. It was given to me above and I just used it.
x + (32 - 1) is the right edge of your sprite. After dividing it by 32, it is the grid location of the right edge of your sprite.
if(key[KEY_UP]) { if(levelCurrent[x/32][(y-2)/32].walkable==1 && levelCurrent[(x+(32-1))/32][(y-2)/32].walkable==1) { y-=2; } }
This code tests whether the future position of the top left and top right corners of your sprite is walkable.
You need to do the same thing for the other three directions. When moving down, test the bottom left and bottom right corners of your sprite against their grid locations. When moving left, test the top left and bottom left corners of the sprite. When moving right, test the top right and bottom right corners of the sprite.
Ok I found the error in the collision. I forgot to add in the characters x and y so it was him colliding not the top left corner of the screen.
I'm still having the issue where the map jumps whole tiles on occasion though.
I replied over at your gamedev.net thread.