beoran, on Sat Jun 6, 2009 3:49 PM, said:
SeaGtGruff,
Yes, for now I've always used "push back" collision resolution, even on PC game I'm programming. It seems simple, but it really can get complicated too, because there are situations in which the "push back" fails to push back correctly. Now, I try to solve this by having extra "push out" code that tries to resolve a stuck item or player, but it doesn't help much either.
Preventive collision detection as you describe would be nicer, I guess, so I'll try that. i hope I have enough resources to pull it off. ^_^
Personally, I think the "push back" approach is better (and maybe more realistic) for an adventure game, because it sort of simulates the idea of running into a wall (by accident) and getting "stunned" or slowed down momentarily. But for a maze game like Pac-Man you'd want to use the "preventative" approach, because it would be too frustrating for the player to get caught by the enemy because he or she didn't turn a corner "just right." Of course, that same argument could be extended to being chased through a tight maze in an adventure game.
Anyway, the "push back" approach is very easy if you do it correctly. Basically, you need to save the x and y movements before you apply them, so that if a collision occurs you can un-apply them to push the player back. You don't need to check for each direction separately-- and if you do, it can lead to glitches. Instead, just save both directional changes (x and y), then apply them at the same time, draw the new screen (new player position), then if a collision occurs, un-apply both x and y directional changes at the same time *before* you check for the new movement.
Here's a little demo program I did a few years ago, which moves a little stick figure around a maze of rooms. I've had to make some coordinate adjustments in it for the changes between batari Basic 0.35 and 1.0, so hopefully it doesn't have any glitches in it. But the relevant portion dealing with the collisions (with other irrelevant lines removed, and comments added) is shown below:
loop
rem * get the new change in the x or horizontal direction
p0_x = 0 : rem * initialize it to 0 (no left-right movement)
if joy0left then p0_x = 255 : rem * adding 255 is same as subtracting 1, so move left
if joy0right then p0_x = 1 : rem * move right
player0x = player0x + p0_x : rem * now apply the x movement to original position
rem * get the new change in the y or vertical direction
p0_y = 0 : rem * initialize it to 0 (no up-down movement)
if joy0up then p0_y = 255 : rem * adding 255 is same as subtracting 1, so move up
if joy0down then p0_y = 1 : rem * move down
player0y = player0y + p0_y : rem * now apply the y movement to original position
drawscreen
rem * now be sure to check collisions and take action *before* looping back to get new movements
if collision(player0,playfield) then gosub knock_player_back
goto loop
knock_player_back
rem * un-apply the previous movements to move the player back to original position
player0x = player0x - p0_x
player0y = player0y - p0_y
return
Of course, if you need to save cycles and/or bytes, you could consolidate some of this, like putting the initializations on the same line (which saves 2 bytes and 2 cycles), or putting the un-apply statements right inside the if...then instead of calling a subroutine (which saves 4 bytes and 12 cycles):
loop
p0_x = 0 : p0_y = 0 : rem * saves 2 bytes and 2 cycles
if joy0left then p0_x = 255
if joy0right then p0_x = 1
player0x = player0x + p0_x
if joy0up then p0_y = 255
if joy0down then p0_y = 1
player0y = player0y + p0_y
drawscreen
if collision(player0,playfield) then player0x = player0x - p0_x : player0y = player0y - p0_y
rem * saves 4 bytes and 12 cycles
goto loop
Note that you do *not* need to redraw the screen immediately after pushing the player back; just loop back and get the new inputs. If the person keeps pushing the joystick in the same directions, the player will keep colliding with the wall but won't be able to go any further, and will be bounced back as soon as the person stops pushing on the joystick.
Michael