Time to begin development!

If you’ve never used PICO-8 before, it imposes a “token” limit of 8192. Tokens include variable names, special characters like . or [], and keywords like function. It’s probably the biggest limitation on game scope, and something of a pain to optimise around once your game reaches a certain size; it’s part of the fun though!

I’m starting with the art and sound from the previous version as a boilerplate, but I’m rewriting the code from scratch to hopefully find token optimisations as I go.

Animation system

First, I wanted to establish an animation system. I settled on the following setup:

--### in _init() ###--

-- start frame, length, speed multiplier
anims = {
    {1,4,0.3},  -- player idle
    {17,5,0.4}, -- player run
    {33,2,0.1}, -- player idle (w/ hammer)
    {49,4,0.3}, -- player run (w/ hammer)
    {6,5,0.45}, -- player roll

    {129,3,1}, -- hammer spin
}

--### in _draw() ###--

-- pick an animation from the list
p_current_anim = anims[p_anim]

-- start with the first frame
-- move to new frames depending on the animation counter
-- mod by length to prevent drawing the wrong frames
p_current_frame = p_current_anim[1] + flr(anim_cnt*p_current_anim[3]) % p_current_anim[2]

It could be more token efficient, but it works for now.

Sprites, animations and shadows

After adding player movement, the hammer, and the enemies (the bases of which were largely similar to the original), I redid the roll animation, and redrew the hammer (I’m not sure why I always kept the hammer in the original hammer as a dull T, but here we are I guess).

I also added a short trail behind the hammer when thrown to lend some extra speed to the animation, and making it slightly easier to parse in dense scenes.

Updated graphics for Icebreaker
The spinning hammer and landing sprite make the physics much more believable

I want the environments to be more clearly defined in this version; the arena is a small patch of snow with icy borders. I might add more subtle worldbuilding elements later, but this is still more specific than the strange enclosure I used before.

Along with this, I added shadows to the player, hammer and enemies. Whenever any of these is drawn, the current frame of its animation is turned to grey, flipped vertically, and positioned 8 units below the entity’s y coordinate.

This adds a nice sense of lighting and mass to the characters, which previous felt a little like floating images.

Shadows are cast underneath game entities
Shadows!

A more dynamic camera

Focusing on the goal of visual polish, I wanted to add something that adds heft and momentum to the game. The original version uses plenty of screen shake and hit-stop pauses to make impacts land, but the overall experience feels slightly (and underwhelmingly) static.

I was inspired by other top-down shooters, such as Enter The Gungeon, to play around with the camera a bit. It’s difficult to add that kind of dynamic camera movement without twin-stick controls, but I found a decent solution that adds the feeling I’m looking for.

An example of Enter The Gungeon’s dynamic camera
Enter The Gungeon's camera sits somewhere between the player and the aiming cursor (Credit: Devolver Digital)

A similar camera is implemented in Icebreaker
The new camera acts similarly, but anchored to the centre of the arena

The camera now sits in-between the centre of the arena and the player character, creating an energetic feel while keeping most of the action in frame - most importantly, the bits where your hammer could reach in a single throw.

I think it looks pretty great, but I could see the slightly jerky movement causing motion sickness in some players. An option to disable it is definitely a must for future UI.


That’s it for the first proper blog post! Let me know if you have any suggestions or questions about my implementations.

As always, full and up-to-date source code can be viewed on my GitHub (under v2) - it’s a bit of a mess sometimes, but when is it not?

wsasaki