Dev Blog 20: Movement
Well, I did miss my monthly dev blog post because of some big family events and so my work on the game had been pretty limited. I wish I could have gotten more done, but there wasn't a ton of free time for it so not a lot was accomplished. I did work here and there, adding graphics mostly and a few random bug/scene fixes that I came across. The Tavern is looking pretty filled out now, with various junk and goods scattered around. There are no patrons yet, which once added, will give it some real life. That'll have to wait though because I'm not really ready to jump into all the things I'll need to build to have NPCs. In the meanwhile, I figure I can write up a technical article about how movement works in the game since I talked about it in other posts.
Like many games, movement is controlled by pressing the W,A,S, and D keys. When pressed by the player, we'll get a message telling which key was pressed. We then can use that to determine which directions the player intends to drive the character. I wanted to allow free movement, meaning that I wanted to not restrict the character to the center of a cell in a grid or making the player auto walk on certain predetermined spots. I also wanted to allow the player to move diagonally, which is not usual in a zelda styled game.
So as a key is pressed, we know which directions the player is intended to move. We remember that direction vector for later use. We then need to make sure that the player isn't going to walk into a wall or object that they shouldn't be allowed to move through. This is called collision detection. Collision detection can be done in a ton of different ways and it can be as precise as desired. For this game, it doesn't require too many calculations because of the blockiness of our characters and world. We start with a bounding box that wraps around the feet of our character. (green in the picture below) To detect if something is in front of our character we stretch a line out from the far corners of the bounding box. (red arrows) We check to see if those lines touch or go through the bounding boxes of other game objects. These objects are predefined to belong to collision groups and we filter out the groups we don't care about. That list of what we care about are set on each character. So basically we can say things like, players won't run into background objects (the ground) or other players (if we even have that). Bad guys won't collide with other bad guys. Both groups will collide with world objects (trees, shrubs, rocks).
If we detect that we've collided with something, we allow the player to move as close as possible (without walking into the other object) and then we stop moving them. Now, something that was immediately apparent to me after one test run was that you can easily get stuck on corners of objects. If one of the red arrows just barely happens to touch the edge of a box the player won't be able to move past it. I researched how older games handled this and found that a good approach to take in these situations is to gently nudge the character a different direction and then try to move the intended direction. This is best shown through an animation which you can check out below. The key part of all of this is that you won't want to do this when hitting an object head on. Just nudge when only the corner hits. So to accomplish this, we also use an additional line stretched from the middle of the bounding box (blue lines above) to see how much we're colliding.
First we check the red lines. If we have any collisions there, then we check in the inner lines. If we find that even the inner lines collide, then we stop the movement. However if we find that one of the blue lines does not collide with anything, then we know that we're on the corner of something and can use that information to nudge our character on whichever side was walkable.
Lastly, this can result in a odd animation bug when walking against a diagonal bounding. The player will hit the line, get nudged slightly, and then hit the line again. This makes them flip back and forth quickly and it obviously isn't what I'd like to show when this situation occurs.
To fix this, we also add a very short cool down period when we manually face the character during the nudged process. This will keep the character facing in the general direction that the player is directing them and it won't flip as often and yet we'll continue to nudge them along the diagonal.