Day 5: Twin-Stick
2026-03-19, 2026-03-20
With the arena finished up, I now wanted some player interaction beyond moving around. Of note, there are some dips in FPS at random intervals, which indicate there are some significant performance troubles I'll run in to as I continue building upon this game. I'll need to understand and improve them eventually.
Debug Mode
I moved all the "debug" information into individual functions, which can be toggled on and off. It makes working with them easier to modify.
Player: Health and Essence
My first changes were slight, adding a player health and essence tracker to the top of the page. Design wise, I think it'd be neat to have the health and essence in some combined display, and as essence increases, it threatens health in some way. I think of chains around a heart, growing tighter, until they crush it!
I implemented a simple function to increase essence by 1 every second. This turned out to be a bit trickier than I expected. In the end, I settled on this solution:
(var essence-second 0)
(fn generate-essence []
(local (i f) (math.modf gameclock))
(when (> i essence-second)
(set essence-second i)
(mod-essence 1)))
The gameclock here is an accumulation of time the game has been running, as a
float of seconds and milliseconds. Using the math.modf function, I can get
only the second value. I compare that integer to the essence-second value, and
when it's bigger, then I increment essence-second. This, roughly, happens once
a second, with an FPS above 60. With a value below that, it will tick slower.
There is likely a better solution here, but I didn't spend more time on it.
Player: Attack
The next big hurdle was a basic attack. When the player has essence, they can do a basic projectile attack for 1 cost. The projectile will start at the player, and travel in the direction of the aiming cursor, which is currently tracking the mouse. I've run into this challenge before, and I never solved it then, but now I'm getting closer. The solution I've gone with is normalized vectors. Given the player's position, and the cursor's position, I can generate a vector, and then normalize that vector, and apply it to the projectile.
The first challenge I did not initially account for is that the mouse and player live in two different coordinate spaces. The player, along with the rest of the "world", get translated when moving around. The cursor, along with the other UI elements, do not. The solution to this is simple, though it took me too much time to arrive at it: apply the translation values to the mouse when calculating the vector values. I can verify my coordinate are correct by turning on debug mode, which draws a line between character and cursor.
The remaining challenge, and one which perplexes me still, is normalizing the vector and applying it to the projectile. Because the coordinate system starts in the top-left, I may need to subtract values I would otherwise add. I also need to account for time and FPS.
These are the little gotchas that familiarity with an engine would overcome. For me, I just have to live with them.
Time: The Greatest Enemy
I draw close to the finish line, nowhere close to finished. My ambitions for this game were very high, and I knew that going in. I've made great progress, and I feel that I've learned quite a bit, but unfortunately I don't see myself inishing this game as I would like to. I'll give some thought to options working upon what I have, otherwise I'll get this to a point and just upload and submit it unfinished. It's unfortunate, but ambitions do be like that sometimes.