Swashbuckler Seas Development Reflection based on a walkthrough of its GDevelop events sheet
Let me begin by saying it’s one thing to be theoretically cognizant of the “defined... architecture for the overall game program” as:
“1. Initialisation (Init or Start)
2. Game Loop (Main or Update)
3. Termination (Cleanup or Quit)”
--and another thing altogether to develop a game large enough (ha!) to experience it and really get your hands dirty (CodeHS, 2022).
I’ve been using the following excellent flowchart from the blog Read Write Code as a general reference for this structure:
However, in truth, this is the structure that has intuitively arisen anyway in the development of Swashbuckler Seas, and I’m inclined to think that, as long as computers continue to work the way they do in terms of processing, this is how any and all games look as programs.
As the sole “programmer” on Swashbuckler Seas (if you can call looking up whatever arbitrary language GDevelop uses for otherwise standard conventions, “programming”) I’ve made it my business throughout this piece of assessment to refine my programming and coding practice. The benefit of using something so accessible and simplified as GDevelop, of course, is that this refining of good coding etiquette hasn’t become sidetracked by simply not being able to speak the programming language-- for the most part.
I’ll admit it-- I didn’t organise all the parts of the game program into appropriate groups until I was absolutely waist-deep in mechanics, both used and discarded, cherry-picked and adapted from all sorts of YouTube videos and GDevelop forum posts.
When I did, however, I think I actually realised satori.*
Moving on, the Start phase of the program runs as follows:
The music begins. Any relevant timers begin. Variables are set to their defaults. The camera is set.
Now, I have no doubt that to the experienced eye (i.e. not mine), literally none of this is new or particularly surprising. I also have no doubt that there is likely a best practice for what order in which these things should be initialised-- off hand, I wonder if it’s more prudent to have the timers begin before the music, for example. In a pragmatic sense, it probably doesn’t matter, but I wonder about these things in terms of keeping code clean and extending consideration toward anyone else who might also be handling the code.
(In this case, obviously, there was only me. Needless to say, what you won’t see in any of the “code” throughout this post is the struck-through remains of unused, omitted or disabled features and mechanics, which I cleaned up for the final version, and which would have definitely presented issues for any fellow programmers on the team).
Now here’s a “learning moment.” I should probably not begin the Game Loop proper with the health/firepower upgrades mechanic.That probably belongs after player controls, player health, scoring, etc. Chalk it up to something to bear in mind in future. Incidentally, this was one of the last things I added to the game, and I think in my search for a fresh start on a feature, I simply created a new event underneath the Start Phase, and the rest was history.
Being one of the last things implemented in the game, I’m proud to say that I actually required very little assistance from online sources in writing this “code.” I already knew how to set a condition for the player clicking on something, changing scene variables, the difference between a global variable and a scene variable, creating objects (and on the correct layer, too!), starting timers, and playing sound effects.
(The Score I had to change from a scene variable to a global variable when I wanted to carry it into the “Game Over” scene. That was an exciting “find and replace,” let me tell you.)
Upgrading the maximum health hearts was a struggle, actually. I was nervous to change the code around the hearts as I had adapted it from a tutorial and there were parts I didn’t fully understand. I experienced what I have no doubt is the classic programmer anxiety around pulling one block out of the proverbial Jenga stack and having the entire thing simply stop working unaccountably, creating an extra three hours’ work for me.
Nevertheless, I persevered and talked myself through the logic of the events (as I like to do while coding) and the entire thing turned out to be much simpler than I had anticipated.
Implementing the 360-degree spray of cannonballs was really fun. Again, I’m glad I didn’t try to implement it earlier, because in particular I needed to be able to manipulate object instance IDs in order to determine the angle of each of the six cannonballs. And I couldn’t do that until I had finalised the health hearts system.
My intuition as to the “cost” of these Upgrades in-game-- i.e. how much of the score the player must spend to earn each upgrade, turned out to be fairly spot-on. The exception was the multi-cannonball upgrade, which had to be nerfed by increasing its cost to 2000 points, as it rendered an already comically easy game positively braindead once you accessed it.
Now this is interesting. Originally, the game retained the original controls we were instructed on our “Asteroids” prototype: mouse only. This, to my thinking, was a boon, considering it made the game very accessible to mobile players, who represent an audience with a terrifying growth rate within the games market, to the point where some researchers have actually identified “a gradually shrinking traditional gaming market” (Cai, 2022).
However, during collaborative team discussions, we decided we wanted the player movement and the player fire to be more separated, and a little more nuanced. We wanted the player to have more control over on-screen elements using the cursor, while enabling them to continue to move around the map. This was especially important when considering the slide-up Upgrades menu.
Other than that, I would note that it was fun to learn how to manage a separate weapon sprite from a player sprite, and I remember thinking that this would be a useful thing to understand for future game development. In this case, it was made simple by the fact that, as reflected in the code, the cannon would “Always” need to be in the center of the ship. (This in itself meant that I had to get to grips with the Points on the sprites, learning that sometimes GDevelop considers certain “position” actions using the “Center” point, and others using the “Origin” point, and there’s no way of knowing in advance what the program will do).
This was frustrating. I found a YouTube tutorial on creating an arcade-style score with leading zeros. (Or at least, a demonstration of such a feature with, well, something to be desired in terms of explanation and detail), but no matter how hard I tried, I kept encountering an issue whereby the number of leading zeros at the beginning of the game changed once the player began earning points. I’m sure it’s actually a very easy fix, and if I set my mind to it, it’ll only take a maximum of half an hour. But it fell to the bottom of the bugfixing priorities.
In deciding that the map of the game world would extend beyond the window, of course the issue arose of enemy spawning location. In its Per My Email days, this part of the events sheet simply had enemies spawning in random spots on the map. Simple!
However, now we needed enemies to spawn anywhere on the map, except in the field of view of the player. For the longest, most irritating while, it somehow slipped my mind to create variables representing the extreme sides of the map, and instead I had coded hard co-ordinates into the enemy spawning mechanic. When I finally saw sense, I was able to respond to team-member requests to alter the size of the map with much greater ease.
To further comment on enemy spawning, likely the most interesting feature to me at this point, yet also the smallest detail and also the most last-minute detail to be added, was the spawn rate.
One of the core pieces of feedback which was consistently raised by playtesters was the difficulty of the game. It was possible to sit in one spot, fire in all directions, and not see a single enemy for minutes on end, earn 1000 points shooting off-screen enemies, purchase the multi-cannonball upgrade, and then you could really grind up the score, rinse and repeat.
I had the rough idea of implementing a simple time-sensitive difficulty scale. The simple addition of a timer for “elapsed time” and tying it to the spawn rate of enemies actually added a rudimentary additional level of challenge to the game. It added, in fact, a sense of rising tension and urgency to gameplay.
Given more time on this game, I would have liked to have playtested this thoroughly and refined the specific values.
Originally, the health restore item was a rum barrel, as I thought it fitted with the pirate theme. However, I created the sprite in a rush, and no playtesters were really sure what to do with it. It also created confusion whereby if playtesters learned it was a health restore item, they also thought they might pick up points by running into debris.
If I’d had the time, I would have added an animation whereby it rotated and behaved more like a barrel, and less like a badly-tweened Flash animation prop circa 2008.
There’s not a whole lot to say regarding the collisions in the game, other than the fact that it’s pretty clear at this point that I took Per My Email and built on it for this game. There was a lot of logic involved in ensuring objects were created and destroyed appropriately, and scene variables updated properly.
There is an unused variable/function in there called “Push,” which again, is from a tutorial I used to implement the hearts system. The idea was that there was some pushback to the player sprite on sustaining damage, however this was another minor “nice-to-have” bugfix that fell to the bottom of the priority list.
My gods, if someone had told me earlier that GDevelop had a “for each” function!
And I think I just spotted the issue with the “Push” function. I forgot to introduce the variable “Damage.” Cue head-smacking.
Need I say more here? The Health variable is equal to or less than zero, you die and we change to the “Game Over” scene. I should have probably removed the “death” sound effect, since: a) it’s me indecorously going “blegh” into a microphone, and b), it’s inaudible considering the louder “Game Over” jingle which plays on the scene change.
*The state of awakening in the Zen Buddhist tradition.
Cai, X., Cebollada, J., & Cortiñas, M. (2022). From traditional gaming to mobile gaming: Video game players’ switching behaviour. Entertainment Computing, 40, 100445. https://doi.org/10.1016/j.entcom.2021.100445
CodeHS. (2022, March 3). Teaching the Game Loop. readwritecode.blog. https://readwritecode.blog/teaching-the-game-loop-4c264398384
GDEV in 60 Seconds. (2021, April 5). GDevelop 5 Score and Countdown Timer [Video]. YouTube. https://www.youtube.com/watch?v=qraa4xgvLmY
NT_exe. (2020, August 24). Health points as hearts in Gdevelop [Video]. YouTube. https://www.youtube.com/watch?v=sKVQsdaH3l8