by Jonathan Port
Continued from Part 3
Press a Key to Continue
The Kickstarter was done but it was business as usual in dev land. There was a mountain of work to get through in a short period of time: nine levels to build, nine boss fights to build, a raft of effects to implement and several more layers of polish. There were also little issues and niggles that we were picking up. Just before the demo build was cut (some weeks before) Rob had been play-testing and mentioned in passing that he thought the laser fire wasn’t reacting quite as quickly after your flip the ship compared to the original iOS code. John Ogden had originally laid down the early groundwork in the Unity build and I knew how he had implemented the code for the flip manoeuvre. Essentially the pitch of the ship alters from 0 through to 180, and at each extent the direction state will be facing either left or facing right. The lasers are not allowed to fire as the ship is pitching, so I knew the laser code would only kick in at 0 or 180. I therefore knew the code was correct and I vaguely ignored Rob’s comment. Then during the start of the Kickstarter campaign somebody else mentioned the same thing. Hmmm, I’d better take a look. I debugged and determined that the code was behaving correctly as I expected. As soon as the ship has finished pitching, its state allows firing. I pored through the code a bit and realised that although physically the laser cannot shoot until the ship has fully flipped, the reaction time of the player meant that you would end up with a half-second delay. I pulled the code around a bit to alter the timing of pitch and direction states and made a mess. The animation cycle of the ship is tied in with the pitch and everything went wrong. I decided since it had only been mentioned once that it would be best to just ignore the whole thing. Never ignore an obvious issue, it will just come back and bite you some time later! It did. Someone else was now mentioning the same thing and I wasn’t going to get away with it.
So, I went back and re-read through the code and state changes and the solution just appeared in front of me. I had been looking at the direction states for a solution when I should have gone back to the pitch. A simple bit of normalization code and the timing issue resolved on its own. So now the laser fire is enabled as the ship reaches the halfway point of the flip (90-degree pitch) allowing plenty of leeway for the reaction time of the player. This change gave a much more reactive feel, you can zoom away with a Hunter on your tail, flip around and still have enough time to fire off a salvo of laser bolts to take it down: a trick that was very difficult to pull off previously. Lesson learned.
Around this time, I was working on the Sentry Guard ion cannons. I re-did the graphics for it about three times before settling on its current state. The first go was a bit spiky and not intimidating enough. The next go looked nicer but wasn’t quite the right style for the game, it would have sat nicely with 16-bit graphics of an Amiga, but not the more pixelated look of the 8-bits. So, I pixelated that out a bit more, but still wasn’t quite happy, so I re-did it and came up with a graphic that fit with the chunky, pixel look of the other cannons and gun turrets in the game. It’s important that the style is retained throughout the game. It’s no good having something chunky and pixely sat next to something that is smooth and shiny. It’s the same for the explosion effects. There are lots of off-the-shelf particle effects in Unity that could have been thrown in, but it would result in a disjointed looking game rather than a retro looking game. You have such a high resolution to play with on modern hardware that it actually takes some effort to pixelate and get the right look across all game effects! The Neo Retro philosophy that we are following does not exclude consistency. It’s a surprisingly tricky process to decide: when you should look for a modern solution and when you should stick with something more retro. With Hyper Sentinel, I believe we got the balance just right
The code was progressing fine, but I now had very tight timescales to meet. There are many things during game development that are not obvious when looking in from the outside. For our backers we had set a delivery date that I obviously needed to meet. But the reality was that my real delivery date for first draft completion was much sooner than that. Lots of things have to be in place for the various game review cycles that have to be done by third parties. I had a plan that would hopefully get all the levels and assets in place early, with filling out and polish coming afterwards. We discussed timescales together on a Skype call and Rob suggested that John help with the game metrics, and analytic data capturing during gameplay. That could then be aggregated to form the basis of the in-game medal system and the achievements that are required by the console versions of the game. I noted that the clocks were going forward that weekend too – another hour lost.
As John and I continued with the game code, Rob was busy organising all the other stuff that goes into making a game, including marketing. It was a nice surprise then when, at the end of March, Hyper Sentinel received a two-page spread right near the front of Retro Gamer magazine! I knew it had been possible that we’d be in there somewhere because I had done an interview for them a few weeks earlier during the Kickstarter campaign. But a full-colour, two-page spread was more than I had hoped. I even got my mugshot in there too. I checked for paparazzi around the house when I got home that evening, but there were none. I considered wearing my Hyper Sentinel T-Shirt and popping into the local Game store at the weekend, but decided I would be better just cracking on with the code. My wife Sarah, noticed that our Denby cups were also in the picture (with Rob holding one). She said we’d better keep hold of those in case a collector wanted a famous set of cups in the future! They are nice cups.
By the end of March, I had finished the layout of all the levels and that was a small milestone because it kept the game on track to meet the first deadline for a ratings build. We wanted to get the ratings done early and out of the way for scheduling reasons, but that meant the game needed to be feature complete. Not necessarily polished but with the main gameplay in place, all the level designs, enemies, and bosses had to be in place. The game was feeling good and solid but was lacking a lot of polish in many areas. The biggest challenge was building the bosses. So far there were four completed which left eight still to do, and those would be much more complex than the others. I had four weeks to finish a first pass for all of the bosses. If you do the maths, that’s half a week for each boss. It was going to be too difficult to do properly. I decided the most efficient way would be to put the finalised boss designs in but give them limited and similar movement patterns to each other. We could expand on that later down the line. Meanwhile the Nintendo Switch I had purchased earlier that month was looking sorry for itself in the corner of the room. Sorry Zelda, but this was how it was going to have to be for a while.
At the start of April we received some great news; confirmation that we would be good to go for the Switch version of Hyper Sentinel. I knew Switch was going to be a perfect match for the game. Incidentally, I would have liked for the game to be on Vita too, but it just wouldn’t have made any commercial sense. I put together some gameplay videos so Rob could make the announcement to our backers and then the wider world, but I had to be careful doing these, as the bosses weren’t properly done yet and there was still quite a lot of unpolished content.
Nevertheless, at this time it was one of the first confirmed shoot ‘em ups for the Switch, which was exciting! Speaking of bosses, that was my entire focus at the time. I spent the week putting together the Level 6 boss. The boss on level six contains two Battle Orbs that spin around and introduce the Sentient enemies. The Sentients hunt in pairs, tracking your position before pouncing forward. They mostly worked, although sometimes crowded together which I needed to fix. My deadline was to have the first pass of all bosses finished in time for Easter. One of the nice things with Unity development is that it is very heavily component based, so I can write small action routines, attach them in, and then later replace them with a set of all-singing, all-dancing routines. For the time being, this approach was ideal for the bosses, as I was basically creating prototype behaviour scripts for them.
Level 8 boss, Pytharg, took a bit of fiddling to get right. I had made a few errors in the curve plotting which was causing the boss to ‘hyperspace’ at the end of a movement cycle. I think the error was partly due to fatigue and general tiredness; I spent an hour or two that night trying to fix it without any real focus, but the next day I fixed it in about 15 minutes! I was beginning to find the initial boss framework a bit tiresome to make and couldn’t wait to get them laid out for every level, then I could go back through each one and add proper motion, transitions and effects; that’s the stuff I really enjoy doing. It wouldn’t be long now though, the Level 12 boss layout, then Level 11 (much easier) would hopefully leave us on target for two weeks of development to get a level select screen and other game modes sketched and laid out. Yes, that’s right, at this point in development there were no option screens or level select screens or medal screens or general UI elements in place at all. Still so much to do.
I decided to upgrade to the latest version of Unity. Previous upgrades had generally gone well, with little in the way of issues to resolve afterwards. This time, that was not the case. I installed the latest version and then opened the project file, waiting patiently for all the assets to be imported. The environment opened up and only one error appeared in the console, not too bad, I thought, could have been worse. A quick look seemed to indicate that one of the methods of the Animator class had been removed. I couldn’t seem to find any equivalent method or much in the documentation on what had happened to it. In the end, I restructured the animator state machine, so I no longer needed the method anyway. I carried on to check that the game was still functioning okay. Level 1 looked fine, but the enemy destroyer decks on all the other levels had disappeared! Not the best thing to find to be honest. On closer inspection the game objects that build up the destroyer were all present, but nothing was being displayed; just a pile of destructible objects floating in space. I kept looking. It seemed that every game object from the destroyer prefabs now had an empty sprite property. After some playing around with various processes and functions, I knew the only way forward was to manually add back each and every asset to the prefabs. Three hours later I was back to normal. Playing the game in the editor wasn’t looking great either, I was getting screen tearing all over the place. I did a quick build of the game and thankfully the compiled code ran smoothly at 60hz, so it had to be an editor issue. A bit more faffing and I found that turning on the new Metal support for the editor seemed to smooth things out somewhat (all my game development is done on an Apple Mac). By 11pm that evening I was ready to continue finishing off the first pass of the level bosses.
We were now a couple of weeks into April and gremlins were appearing all over the place. When I noticed that the Arc-Steamer mines seemed to be destroying immediately on release instead of on the correct timer, I set about debugging everything. The mines are pre-created and stored in an object pool due to the sheer volume that can be created. This means that when a stream of them is released, they are just pulled out of the pool and made active. When they explode, rather than being destroyed, they are reset and made inactive. So I checked that the pool was behaving, which I was sure it would be since it is a generic piece of code that is used in many other places without issue. After confirming this was all okay, I debugged and logged the timer code for how long the mine stays on screen before exploding. I set the timer to a really high value and the mines were definitely ignoring it. I scratched my head and decided to look at the animator instead. I was using a trigger, so that when the timer goes off, a trigger fires and sets off the destruction animation. Once that is complete, the mine is put back in the pool. I stared at it for a bit and then noticed that the state machine wasn’t being reset back to its starting state. Hmm. So, in a rush of intuition I added a new flow arrow to the diagram and dragged it back to the starting state, and then tried it out. Fixed! It seems I must have missed a bug in the previous version of Unity’s animator that was resetting the state. Now that, that was fixed it had triggered another bug (which is only noticeable if you are using pooling). Adding further to my gremlin woes, I had also upgraded one of the Unity assets I was using, and that had bugs too! When I was firing at gun turrets or bosses, rather than them flashing white during a hit, they were disappearing from the screen entirely. Arggh! I found a quick workaround, but it didn’t fix all the issues I was finding. By this time it was far later in the evening than I thought, since my watch had (unbeknownst to me) stopped working and I thought it was only 11.30pm. It was in fact, approaching 2am, I was tired, but hurriedly put together a mildly angry email and fired it off to the company who made the asset. By 9.30am the next morning, I had received an email of thanks and a notice that the bug was fixed and available to download. Wow, now that’s service! I humbly replied with another email thanking them for their effort. As I was in a debug kind of mood so decided to spend a bit of time with the profiler and optimised a few routines that were spiking higher than they should for what they were doing. I hoped there would be no more gremlins for a while now.
There was going to be more pain in April though. I usually go for a long run on Sunday mornings. In fact, I often solve many problems during those runs as it helps me to focus on my thoughts. This time was to be different though and I discovered that pavement is a very hard surface. Bad perception on my part meant that I thought I had judged the height of a curb correctly: I hadn’t. All I remembered is falling like a tree and feeling a very hard surface hit my chin. My first concern was to do a quick system check to make sure I hadn’t broken any limbs. That area seemed good, thankfully! The next concern, being British as I am, was to quickly get up and run along hoping nobody had witnessed my embarrassing fall from their front room windows. As well as my chin I had cuts on my knees, hands and the tips of my fingers. It is the latter of these wounds that caused most of my problems. Making a game can be mentally painful, but let it be known that there is code underpinning in Hyper Sentinel that was also physically painful to write; key-press by searing key-press.
Nearing the end of April, the deadline was soon going to be upon us. I was busy working on UI for the new option screens and medal layout. At the same time John had been completing the code for the medals and putting unit tests around them so that we didn’t accidently break them later down the line. We needed to merge the code with our fingers crossed – there wasn’t going to be any time for issues – and I also had a sprint deadline at work. My code was pushed to Git – our distributed source code repository where we all share and maintain the game code – as was John’s code. Once the branches merged it compiled, ran, and nearly worked first-time. The systems were talking together and I could cycle through the medals – cycling through the medals proves the interface works – but there appeared to be a few teething issues, as the descriptions of the medals weren’t displaying correctly. A quick debug, revealed I was passing a level number value into a routine that was asking for a medal number. My fault! I hadn’t picked it up before because I was using a stub routine that was just returning random data to test my user interface. The other issue was a little more subtle, and without going in to too much on the technical side, it was due to how C# handles capturing variables for closures within coroutines. Sound nasty? Yeah, it doesn’t cause a graceful error that can be tracked either. I made a simple refactor of the code and it seemed to fix it, but I couldn’t be 100% sure due to the nature of the bug (turns out it worked as I never saw the problem ever again). There were some issues retaining and saving out the medal data too, but I decided I would blame the Unity serializer for that.
At the start of May we were preparing for the Switch announcement. Better than that, we were showing off a Nintendo Switch trailer for everyone to see, and Nintendo were going to help us a little by promoting the announcement on their YouTube channel; a pretty cool thing indeed. There were lots of other things going on at this time too. The ratings submissions seemed to be going well with an ‘E’ for everyone coming through so far, which was what I’d been hoping for.
From what Rob was saying it seems the process is wildly different for each territory. Some are happy with videos, others happy to go off of trust, some require hand-written letters before submitting, and others want the content delivered on a USB stick rather than digitally! As always,, Rob was on top of it all. The next goal was to get most of the game together and ready for preliminary Xbox submission. We all sat and chewed on the large volume of code and paperwork still to get through. Things to discuss included: platform holder requirements, territory localisation, menu screen completion, content, polish, leaderboards, and much more. Still so much to do. The elephant waited for us to finish our discussion before quietly entering the room and pointing out the fact we now had three weeks to finish the majority of the content. Okay, so that was going to be tight again! I needed to finish the bosses and get all the menus in proper working order for the various modes and completion statuses. I also needed to go through the game code and find everything that required language localisation (I hadn’t picked up on the need for this earlier in the year!) and then find a cunning way to adjust the code with little disruption so that it could work from language resource files. I hadn’t done the pause screens yet either! Meanwhile John was on to the console port work, achievements, CRT filters, screen modes, and leaderboard systems. In for a penny, in for a pound.
Ratings! That seems so long ago now that I have almost forgotten how much of a pain it was. I had prepared builds for ratings before, but usually with a team of 20–30 developers working on it and a publisher to do the actual submissions. I have since learnt that while publishing is significantly less complex than development, there is still a huge amount of work to get through, and it must be done repeatedly and differently for each ratings board and each platform. Looking back, this difficulty with ratings should have been the first clue that things were going to take a lot longer than we expected, self-publishing a game on multiple formats.
By the end of May it was time to take a break. It had been a tough slog getting the level completion screens completed with various bits of fanfare. It’s not particularly hard work but there’s a reasonable amount of code required to pull various UI elements in and get them operating smoothly together. I had managed to get first pass completion of the pause screens, which was mostly an exercise of reusing code from the main menus because we are allowing players to change the various settings (volume, graphics modes etc.) on the fly mid-level. It ended up a bit more work than expected, mainly due to the time flow in the game, which is halted during a pause. This was also affecting the animations in the menu panels (such as fading in and out). I hadn’t anticipated this when doing the menu code previously: it’s stuff like this that eats up your time. Nevertheless, a whole lot of work had been completed in those last three weeks, and quite frankly, I was knackered! Good job I was going on holiday with the family for a week then! Time to leave the keyboard at home and drink some beer!
When you code as a day job and then make games during your evenings it can sometimes feel as though you’re missing out on stuff like just sitting and watching a film with your feet up. It is good sometimes to just take the night off and eat pizza, but most of your time must be spent coding and creating. I had a great holiday, but those who love to code (making games or otherwise) will know that feeling of being away from the keyboard for more than a few days. It’s like an itch to just get back and make something. Rob Fenn, our awesome musician, completed most of the new music and speech for the game while I was away, and a little email on my last day on holiday meant that I knew what I was going to do as soon as I got back. I plugged the music in and, as expected, it sounded fantastic. The game was feeling good – I’d played it so much over many months – but with the new music in place and a week away to reflect, it felt nice being back at it. I knew our backers and fans and hopefully many more were going to really love playing Hyper Sentinel. It was now time to get it feature complete!
Rob Fenn did a fantastic job with the music, and I really love the digital voices he added for the game too. I remember one of the quotes from my father’s book; Hints and Tips for Videogame Pioneers: “One thing that became very clear to me over time was the importance of music and sound effects, because they actually carry a great deal of the emotional content in a game”. Rob understood our Neo Retro philosophy perfectly, and his chiptune style soundtrack simultaneously prods at your nostalgia, whilst being technically beyond anything you could dream of achieving on a retro system.
I am particularly fond of the boss theme. One of the references we gave to Rob was the Dr. Robotnik boss theme from the original Sonic – perhaps you will recognize the influence when you play Hyper Sentinel.
We were getting close, but still none of us were entirely happy with the colouring of the decks. Rob went and got some expert feedback from an Art Director friend he knew in the industry and this made a huge difference. Adjusting saturation levels and the like gave the enemy destroyer far more depth and the gameplay graphics really began to pop out. As well as that, I was now on to yet another polish layer. I was progressing with adding a ‘white hot’ glow to the enemy bullets so they would quickly be identified during frantic action – prior to this the enemy bullets were solid red.
The game was progressing, but it was becoming apparent that the volume and complexity of the port work meant that a delay was likely to be incoming. Initially this was just a small delay and at least it meant I could continue with adding extra polish for the game. Unfortunately, that delay became a longer one by January 2018. We had still been confident of getting through the platform specific code in reasonable time, but the timing had landed us right in the middle of game release silly season. October, November, and December are no-go areas for Indie games, to put it frankly: it would have been commercial suicide. There are so many AAA games being released during that time that there is literally no space to promote smaller games. We really wanted to get the game out for backers in time for Christmas and we sought advice to see if it was possible, but in the end it simply wasn’t sensible. Despite all of our very late nights and hard effort, we just couldn’t hit a 2017 release.
When we delayed to January 2018 it seemed like such a long time away, we couldn’t imagine missing that window. We decided to use the time to add even more polish to the game – extra touches like the “Boost Attract” and “Death Dodge” which we knew would add further quality – after all we had plenty of time! Then there was the opportunity to produce the pioneering “Mixer Mode” in partnership with Microsoft, which we simply couldn’t ignore.
Ultimately, we underestimated the amount of bespoke code, even when using a cross-platform engine like Unity, which would be required. Some platforms required us to completely re-write the save/load structure or re-write the leaderboards. We also underestimated the complexity and variation in requirements for each platform and the sheer volume of work in the publishing process. Above all, we simply didn’t have enough developers to work on these things concurrently, so we had to juggle from one platform to the next.
Suffice to say we have learned a huge amount and we have also built a solid code foundation, which can be re-used for subsequent games instead of needing to develop everything from scratch.
We are hugely grateful to our Kickstarter backers for their understanding and support throughout this process.