Build 104
Hello everyone!
Life happens and it has been a long time since the last update and I’m sorry for the wait. However, this update brings lots of new things, so let’s get started!
TLDR, here’s some gameplay showing most of the additions:

Eyecandy
First some eyecandy, before I make you read huge walls of text ’^^. I made a lot of polish/cosmetic updates that add a lot to the look of the game!
Signs
I added big signs in the sky announcing the day number, making it a bit easier to track your progression.

Moon and sky
I made the moon a little grayer and added a soft shadow, as well as a soft glow around.
Added stars, with a slight rotation of the skydome. The stars and the moon, as well as the parallax background, are set with the game seed, making daily runs identifiable.
I also made the sky darker at night, and stopped making the sky brightness vary with altitude.

Shadows
Added a dynamic shadow below the player and lowered all ground objects to better set them on the ground and convey the scene depth.

Enemies
I added two new enemies : mines and airships. Also, planes now fly solo but fire salvos of homing missiles.
Mines
Proximity mines that explode if you get too close.
The new explosion interaction makes it that a mine can stop you dead

or propel you forward.

You can also shoot the mines to trigger them before landing on top of them.

Airships
Tethered airships that can carry turrets.

Bullets (yours and enemies) bounce off of it,

and you too!

And as with everything, it can bounce “wrong”,

although even bouncing under can have its advantages

Airships explode if next to an explosion, or if slashed or hit with the laser.
Missiles
Planes now fly alone instead of formations, but fire salvos of anime-style homing missiles.

Missiles can be shot down or slashed.

Gameplay and physics
The first big change is that I went from manually set rules for collisions such as “hitting a turret halves the speed and make the player lose 4 health points”, to only generate an explosion at the collision but make the player react to all explosions by taking damages and a blow-back force, both proportional to the explosion power and the distance from the center of the explosion. This not only replaces elegantly the previous system by doing the same thing, ie dealing damage and affecting the player speed when colliding with enemies head on without having to do it explicitly, but it also allows the player to try to land on enemies at the right angle to earn some damage boost. This effectively transforms every collision into a trade-off between losing energy and a chance at gaining speed and momentum, which is on brand with the core mechanic of the game of spending energy to shoot the gun to gain speed. I’m very happy with this “simple” change as it makes the game much more fun to play and adds another range of skillful moves to master. I feel it also feeds into a kind of systemic gameplay where what happens is not dictated by a closed set of rules but the emergent result of those interactions, such as surfing on clouds, deflecting the bullet from one enemy to kill another, or slashing an airship point blank at full health to ride its costly blast into the sunset!
Next is an overhaul of the sword: I reworked the entire sword collision detection, as it sometimes seemed to miss bullets it should have deflected, and I wasn’t entirely pleased with the way bullets and clouds were deflected. The collision is much more reliable now, clouds move in the direction the sword is slashing and not only away from the general position of the player, and the bullet deflection feels more controllable. The sword is designed to only extend while in the air, so it shouldn’t have anything to do with ground enemies, but it turns out in certain circumstances you can effectively reach a tank or turret atop a hill, so I added collision detection with the sword for ground enemies so you can slash them.
I also increased the acceleration conferred by the gun, as well as the gravity, making the game more dynamic.
RNG
In the last update I talked about my efforts at regulating perlin noises to get uniform random distributions. Well scratch that. I realized I could use a simple hashing function to reliably generate good quality uniform distributions! It’s also faster than making all those adjustments on perlin noises, and behaves much better. I ran some further tests on relevant metrics for my purposes and the results don’t differ from those obtained with a bona fide statistical random uniform function generator. Although I feel like I just rediscovered the wheel after pushing very hard on a big lumpy rock trying to make it roll, I think I’ll still write that blog post even if it teaches nothing and will help nobody, if only to recount that wild journey!
Sounds
I tweaked some sounds, such as making the explosions deeper and bullets hitting the ground softer, and reduced the volume on some sounds (gunfire, wind, explosions). I also simplified some sounds and sound handling to help with performance.
I added sounds for the planes and the tanks: reactor sounds for the planes as well as a diving sound followed by a muted explosion if it happens offscreen, and track sounds for the tanks. I also added a sound effect for bouncing on airships.
Optimizations
Adding new things always take its toll on performance, which needs to undergo some optimisations, and often going back to previous elements to seek further optimisations. Adding visual effects such as the moon, the shadow, moving stars, and physics effects required much optimisations!
I replaced all timers with frame based counters, replaced some costly functions with more efficient approximations, reduced the number of speed lines around the screen, reduced the number of dust particles generated, as well as their lifespan, identified some repeated computations that could be cached, either per frame (sword collision triangle for example) or per game (stars positions and movements, lightray angles going through the player to cast the shadow), set the player trail to 1px wide instead of varying with altitude, and reduced the resolution of the parallax background.
All of this while trying to impact the end result as little as possible. Actually there’s not much of a difference which means it’s less optimisations than cutting needless expenditures!
I spent some time benchmarking a lot of things to find possible systemic optimisations, which led me to apply more aggressive lua optimisations:
- reduce number of global variables used (there were already only a couple, but I made local copies everywhere)
- use random integers for object IDs instead of UUIDs (both much faster, and
pd.string.UUIDseems to be leaking memory, leading to more work for the garbage collector) - on the topic of relieving the GC, I reduced the number of local variables where the result was used only once and inlined operations. I even “recycled” local variables for different successive purposes within the same function to reduce the number of variables of the environment the GC would have to check and free.
- make a local <const> reference for nearly every base and playdate function used.
Here’s the on-device average timing for drawing 1000 random lines across the screen
- gfx.drawLine: 0.1159684
- local drawLine = gfx.drawLine in the file header: 0.1131143
- local drawLine <const> = gfx.drawLine in pd.update(): 0.1127681
- local drawLine <const> gfx.drawLine in the file header: 0.1127213
It’s not much, but doing so consistently ends up doing a difference!
- make function and method local copies of arguments as well as own object attributes
Inside playdate says:
Assign frequently-used objects to local variables If you are frequently accessing playdate API objects like playdate.graphics, performance will increase by assigning that object to a local variable at the beginning of your source file. You’ll only be doing one look-up of the playdate and graphics objects in the global namespace, instead of six.
I wondered for a while whether self object attributes are considered local. Do making local copies only affect object look-up ? Turns out, making local references of self attributes makes accessing them twice as fast!
On-device average timing of accessing self.x 1000 times within an object method:
- self.x: 0.002339595
- local x = self.x: 0.001420549
And it also works with arguments. Or, more precisely, with atomic elements within an argument, also with a 100% gain.
On-device average timing of accessing arg.x 1000 times in a function receiving arg:
- arg.x: 0.002221362
- local arg = arg; arg.x: 0.002720002
- local x = arg.x: 0.001379463
Turns out what is costly is ANY look-up, be it object.x, arg.x or self.x
All of these have the side effect of making the code a bit harder to read and modify, and I hope I won’t have to revisit existing parts too much in the future! There will still be a last round of very agressive optimisations where I will go through every computation and try to hard code every static result (for example I have multiple scaling constants that are used throughout the code and multiplied with different scalars depending on the affected object, that I will replace with the result from that multiplication. However, doing so too early would prevent me from easily either updating all objects at once through modifying that constant or modifying a specific object through its scalar without losing track of the relation with other objects.)
Misc changes
Increased the size of the tanks and bullets to make them more visible. Objects are introduced earlier to make the game feel less empty. The RNG is bypassed for the first object of each type at its point of introduction, so the player will always see the first turret, tank, mine, plane, airship at the same distance.
Enemies are less likely to spawn at night, which I’m considering pushing into some kind of stealth phase at night. I also made the day/night cycle shorter. Changed the behavior of the turrets to only scanning the sky and not trying to follow the player.
Boosting has two distinct phases:
- short A press simply dashes forward (and costs less than before)
- longer A press starts charging to fire the laser and make a more powerful boost
Files
Get RollerBlade
RollerBlade
A fast-paced unlimited arcade shooter for the playdate!
| Status | In development |
| Author | qwack! |
| Genre | Shooter |
| Tags | Gravity, Movement Shooter, Playdate |

Leave a comment
Log in with itch.io to leave a comment.