2026-02-09 2

12:47:22, atom feed.

Here is the curated commit log from this last week's development.

2026-02-03
feat: removed entity action timer; moves are now turn-blocking anims.

2026-02-03
feat: render entity index in graphical turn queue debug visualization

2026-02-03
feat: allow mult. entities in turn queue to move on same frame

2026-02-03
feat: introduce reaction to entity death after attack animations play

2026-02-06
feat: add component to support entity pos interp. during movement

This also updates the camera to move with the player as position is
interpolated, having the effect of a smooth-scrolling camera instead of
a camera that moves in units of whole tiles.

I started this last week of development by simplifying my collection of timer values. I used to have cooldowns for many things: player idling, player movement, player action, player attack, enemy action, enemy attack, etc. Some of these values were used to stall the progression of turns while animations played, and others were just used to determine when to switch sprites in an animation. The different values for timers that would stall turn progression introduced wall-clock-time-related bugs in turn progression, though. In short, this didn't need to be the case in a game where turn progression is gated on player initiative or in other words is not a realtime game. So I reduced the number of timer values and also removed one of my timer components and now just use the general entity animation timer in combination with the entity state to determine when turn progression should be blocked. This allows individual entities to perform turn-blocking animations at different speeds without having to make sure other timer values align well.

I then extended my graphical debugging utility by rendering entity turn indices over entity sprites in the turn queue. This was an obviously-missing feature from the implementation, as there was no way to tell which ghost sprite was which in the turn queue.

After simplifying the my timer and cooldown situation, I then realized that the player moves faster if there are fewer enemies alive. This is because I now also block turn progression on "move cooldown." I do this so that I can show movement animations, which I'll touch on later. If the move cooldown for everyone is C and there are N entities alive, then the player needs to wait at least C * (N - 1) units of time before the player can move again. To address player move speed appearing to change relative to the number of entities alive, I block turn progression on player movement and also on enemy movement, but multiple enemies can initate movement on the same frame (unlike if the player moved) so that their animations play simultaneously. Then, the player waits at most C * 2 units of time before they can move again (maximally, once if the player moves and then again if any number of enemies move after player movement finishes).

Up to this point, I was despawning enemies immediately when their health reached zero. This means that on the same frame the player attacks an enemy and their health reaches zero, the enemy sprite would disappear. The player attack animation still plays for some time, though. I felt it would be more satisfying if the attack animation finished, then a death animation started afterward, and then an enemy despawned. This sequence allows for more visual (and eventually audible) separation between events. To do this, I introduced a new entity state which is .DYING. If an enemy is dying, it starts a death animation, and when the timer on the death animation expires, the entity is deleted. Similar to move and attack animations, death animations block the progression through the turn queue.

Lastly, I added smooth position interpolation during entity movement. Previously entities moved 1 tile instantaneously. Now, an entity's position is linearly interpolated during its move cooldown by the simple ratio of

move_cooldown_remaining / total_move_cooldown

I added a new component in the ECS, moved_from. This simply stores the position an entity moved from if the entity performed movement. The entity's basic position is still immediately set to the destination since game logic operates on map-tile-based coordinates, but for the sake of the render system, we need to temporarily remember where we moved from so that we can interpolate render position of the entity sprite correctly.

On each frame, the camera takes the basic position of the player, so the camera appeared to jump ahead of the player and the player had to catch up to the camera. This, performed quickly, just made everything look jittery. So I exposed the routine to interpolate position during movement from within my Entity module so that my Game module could leverage it, and now the Game module handles computing the new instantaneous camera position based on the player position at the top-level game-update procedure. Once nice consequence of this change is that the camera movement appears much smoother, no longer jumps in visibly discreet map units as the player moves.

The entity death animation timer in this video is set to a dramatic 1.0 seconds, and the current death "animation" just fades the sprite out. Also, there is no movement animation, just position interpolation.