While my map is an obvious grid and my tiles are an obvious grid, the actual movement is not restricted to grid squares and both the player and enemies can move freely. What this means is that I need a movement and collision system that can “run into” and get blocked by certain tiles, namely walls.
Making the player move is relatively simple. Read (keyboard) input, decide on direction, tell player entity to move, adjust coordinates. Of course, it’s a bit more involved with accelerations, friction and walk speeds from definitions, but the basic extendable concept is simple enough. (Plus the camera to follow the player, which will get expanded later.)
Now we just have to make sure they can’t simply walk out a room through a wall:
In simplest terms, my problem is: how do I stop the player from moving into walls. I really don’t want to overcomplicate this with colliders and physics and fancy logic with ellipsis and rounded corners. So the player is a square and the wall tile is a square. When the player attempts to move in a direction, it checks if there is a wall there. And if there is, it can only move the distance that snaps it to the wall. And this works 98% of the time just fine.
The only real problem is how to handle this:
What happens here is that the player is not actually entering a tile with a wall, but rather a tile with a door — that’s where its center coordinate is. And I’m not doing collisions with “everything”, just the immediate tile.
So what I ended up doing is also checking the neighbouring tiles of the tile that could block the player. That is, checking if the player happens to run into a corner of a neighbouring tile. Why am I not doing fixed grid again?
And as far as tiles and the player is concerned, this works perfect:
The final thing is to get the movement “smooth”. (Note that I’m implementing “smooth” movement after collisions, so I can debug collisions stuff with constant movement changes.) This involved 2 parts: acceleration when walking is requested by the player and deceleration when there is no walking happening. Essentially, I’m keeping a current speed of the entity and either accelerating it to the walking speed to decelerating back to 0. I’ve done this sort of logic before, so I’m skipping a lot of maths and details, but the result is as follows:
Even without smooth camera controls (it tracks the player exactly), it looks really nice. Here the GIF is super-exaggerated for demonstration purposes. The actual acceleration is quick, while deceleration is almost instant. The best controls are responsive controls, and the whole smooth speed logic is supposed to be subtle for that nice game feel. Mechanic-wise it makes little difference, but it is very noticeable when playing.
The final touch is that running into a wall zeroes the speed in that direction. It may sound obvious in hindsight, but it’s really hard to notice the “glitch” when playing unless you know to look for it.
There are other things that movement needs to handle. Firstly, effects that can slow the mob. That is, the input requests movement, but should not expect it necessarily. The game may slow the player down or speed them up. And, more importantly, there can be multiple things affecting the movement, for example, an explosion knockback or wind or slippery ice. I don’t have these “other” things yet, so I will mention them when I work on them, but I am potentially anticipating them and thus creating the movement with those features in mind. And I still need mob collisions, but that may involve damage and AI avoidance and such, so I will discuss this later.