Implementing An Upgrade
Today will be a bit more technical than usual. I am going to implement an upgrade for the runners, and you, congratulations, will come along for that journey.
11th Nov, 23
Note: All code snippets are illustrative for readability and may contain errors.
Runners, if you didn't know, are simple units. They walk over to the pile of shards, pick some up, walk back, and deliver them. They are among the first units you unlock, so their complexity ought not to be high. Because of their simplicity, they are hard to make upgrades for. Some of their upgrades include:
— Additional movement speed
— Carrying capacity
— The ability to throw shards from far away
They are neat upgrades, but the runners deserve something with a bit more oomph.
IDEATION
1. Teleportation: Runners that teleport instead of walk
2. Ambition: Runners have increased movement speed based on the the highest point of the pile
3. Gnorpveyorbelt: Runners form a line that acts as a conveyor belt
4. Gnorps must apply: When drones (a unit that delivers shards) perform a delivery, runners get a speed boost
5. Gnorp-Drone Mutalism: Drones pick up runners
6. Timeshift Delivery: Whenever bombers perform timeshift impact (an upgrade to another unit), all runners are jaunted forward in time
So we got some ideas here, some of them good, some of them bad.
Teleportation is an interesting one. If we imagine teleportation itself to have a fixed time (but affected by movement speed upgrades), there would be a breakpoint where teleporting runners would exceed the performance of non-teleporting runners. That introduces an interesting dynamic where low-range damage now has higher value. I can also remove the legs of the runners when they have teleportation enabled, which is funny.
Ambition is a less interesting one, but there is still potential. If you were to have ambition enabled, there would be an incentive to have the tallest pile possible. A crafty player might invest in some low-range damage, and have it as a goal to leave the resulting shards untouched. Said crafty player would then enjoy a significant bonus to the movement speed of the runners, as long as they could maintain that tall-but-not-large state.
Gnorpveyor belt is perhaps the most entertaining option. The runners would form a line, acting as conveyor belt, passing shards to their right. When shards reach the last gnorp, they would be thrown into the building where all shards go. My primary reservation with this upgrade is that it would invalidate some of the runner upgrades, and I don’t quite see a way around it without awkward workarounds. Nevertheless, there is potential here.
Gnorps Must Apply, where runners get a speed boost when drones perform a delivery. Synergy is good, but boring is boring. Why did I even write this down in the list of ideas?
Runners hanging from drones through Gnorp-Drone Mutualism is a decently fun idea. Instead of upgrading the speed of the runners, the player could instead upgrade the speed of the drones. But it would likely not be a sizeable bonus, and it would kind of just turn two units into one.
The last one, Timeshift Delivery, is another one with a bit of synergy. It is on the surface similar to the teleportation idea, but it is entirely different. Bombers with Timeshift Impact would allow runners to skip ahead in time, but the behavior of the runners would be entirely unaffected — they would just do stuff faster. It is elegant, and possibly pretty cool.
DECIDING We have talked about the ideas, now it is time decide. Which one would you choose?
...
If your choice was one of the ideas, you were unfortunately incorrect. The correct answer was two ideas, namely Teleportation & Timeshift Delivery. Both of them affect the game in interesting ways, and are straightforward to implement. The runner-ups (pun!) were Ambition and the Gnorpveyor Belt. If you would have liked to see one of these instead, do not despair for I might implement them too at some point. If you preferred the last two that I don’t even remember the name of, you have failed in your application for Assistant to the Game Designer.
IMPLEMENTATION So we will implement Teleporation & Timeshift Delivery.
Let’s start with Timeshift Delivery.
First we define a variable, runner_iterations. This variable will define how many times runners will be updated per tick. By default, it is set at 1, as every unit updates once per tick. Then we need to allow runners to update however many times the variable runner_iterations decrees. The next step is to pass a mutable reference of the runner_iterations variable to the bombers, so that they may increment when appropriate. That, of course, has to happen before the runners update. It’s time to enter the bomber update function. When the bomber is doing the smashing, we check if the Timeshift Impact upgrade is purchased and if the Timeshift Delivery upgrade is also purchased — if they both are, we increment runner_iterations by the const RUNNER_TIMESHIFT_TICKS, which was set to be 60. That means for every damage instance that the bombers do with Timeshift Impact & Timeshift Delivery enabled, all runners will update 60 additional times. And that’s it!
Now it is time for teleportation!
Runners no longer need their feet, so we get rid of them. They hover slightly above the ground, which makes it easier to identify when you have this upgrade. They also get a white mouth, which sort of looks like a tooth or a third eye.
We should also give them an animation for when they are teleporting. I considered having them do a light bit of shaking when in the process of teleporting, but after trialing it, I determined it looked a bit too noisy. There was also the issue of it not being a particularly good progress bar. I could add more shaking towards the end of the teleportation timer, but that would not solve the noise issue, and also a substantial increase in shaking would be required in order to be a good determinator of how close the gnorp is to finish teleporting. Instead, I opted for a slow ascent into the air. It looks alright.
In order to get the actual teleportation to work, we need to write some game logic, but first there are couple of unanswered questions.
— Should a teleporting runner determine its future position before it starts teleporting, or should it decide right before it teleports?
— Should a teleporting runner prioritize closer shards, or should it be entirely random?
— Should a teleporting runner teleport to a position where it cannot fill its capacity?
To the first question, we can imagine a world where there are 100 teleporting runners. There would be a significant amount of contention, and most runners would be unsuccessful in securing shards to bring back, because another runner would have gotten there first. This of course is only relevant if the answer to the second question is that they should prioritize closer shards. We could add some kind of queuing or reservation system, but that could get messy.
The second question: If a teleporting runner were to pick randomly from the pile, it would slightly dilute the teleportation concept. The breakpoint would still be there, but there wouldn’t be a clear line for when teleporting is more efficient than running. Would that be okay?
As for the third question, we need to imagine a scenario where there are two options to travel to: 15 shards, 5 shards, and 1 shard. In this scenario, the runner has a capacity of 10 shards. Should the teleporting runner always try to find a target where it can fulfill its full capacity? Or should there be a minimum amount instead (dependent on capacity), so that the runner might pick up the 5 shards and the 10 shards out of the 15, but never the 1 shard. Or should it be possible to pick up the 1 shard, but only when there is no other alternative?
After some deliberation, I decided on the following:
— Teleporting runners should decide where to go on the same tick they teleport. They should also pick up the shards on that same tick
— Teleporting runners should prioritize the closest shards, with some amount of fuzzing to avoid the runners being entirely clumped up. This allows for a clean breakpoint that the player can structure their strategy around
— Teleporting runner should always try to fulfill their capacity, but will pick up a sub-capacity amount of shards if left with no other options
We now have a plan! Now it is time for some code.
Runners have states that they abide by. We need to add a couple of new ones.
The seeking state has a look if there are shards available for pickup. If there are, the runner changes to the Getting state, and starts moving. For teleporting we can hook into this behavior, but with a slight alteration.
Now teleportation state is set, and we can add some teleporting behavior.
For the rendering component, we simply to do this And that is it! We have now implemented teleportation! As for the Self::TP_TIME, it is set to be 200, which roughly corresponds with 3/5ths of the possible width of the pile. That is to say, regular runners will be able to move 200 pixels before a teleporting runner will finish teleporting.
SUMMATION We have now implemented two pretty cool upgrades for the runners. See you next week!