About 2½ years ago, I started a new job that limited how much I could work on independent projects (let me tell you, not a fan of policies like this). Still, rules are rules and Voyager, along with my other projects, was put on ice. It was in fine shape at the time, so there didn’t seem to be any harm in leaving it in cruise control.
About 2½ months ago, everything had changed. I was my own boss and beginning the Latin American leg of our journey. BuildDown had shipped, other projects still too green to talk about, and I was looking for a quick win. Voyager was an obvious choice. Problems that had trickled in while I was hands-off grew larger and more serious. The solutions were relatively straightforward… they just needed doing. There were also neat ideas I’d been sitting on for years that I regretted not having in there. A little bit of love would go a long way, so my course was clear: I was going to turn around an update to Voyager, and I was going to do it fast.
But what were those problems anyway, and where did they come from?
From the very beginning of the project, I was wary about plugins. It takes a lot of trust to delegate so much of my game’s functionality, stability, and user experience on a (potentially slapdash) piece of software from a business whose whims and goals may only loosely align with mine. Until recently, relatively little platform-specific functionality came baked into Unity, so plugins were the only way to support the features I needed: ads, in-app purchases, achievements/leaderboards, and analytics. When I exhibited Voyager as part of Indie Prize at Casual Connect USA 2013, the place with mobbed with startups pitching plugins for those services. I was loathe to entrust my game to a company more concerned with getting their big exit than actually providing their service, so I stuck to the biggest, most-popular and well-supported names in the categories in the name of reliability. It worked, at the time.
By 2015, nearly all of them were dead or on life support.
The first to falter was Google Play Game Services. Unity natively supported basic leaderboard and achievement functionality with their Social API, but only for Apple’s Game Center. Feature parity on Android required the use of a 3rd party solution. The plugin I selected was not maintained and fell into disrepair, suffering stability issues on newer devices or versions of Android OS. It was quite the professional embarrassment to talk about the game as part of a PAX Dev panel on science-based games, only to have someone approach me after the conference to show my game crashing on start-up.
Eventually, after setting out on our journey, I got around to fixing it. I was hoping that in the last few years, the Social API would have expanded support beyond a single platform, but unfortunately that wasn’t the case. Honestly, achievements and leaderboards have diminished a lot in importance since the heyday of Xbox Live, so I understand why doing so wasn’t a priority. Weighed against the work required to integrate an alternate plugin (however long that would last) and the pressing need to fix, I gambled that social wouldn’t be missed and just removed it entirely.
While I was in there getting my hands dirty, I noticed some exploratory work I’d done on a new mission type, one that I’d had at the back of my mind pretty much since the beginning.
I closed the project, published the fix and moved on. But the long-dormant seed was stirred.
The next issue came when this email landed in my inbox: “As you may know, iAd Workbench for the App Network will be discontinued…”
I did not know that! So the primary ad network on one of the two biggest platforms in the world was going away. Now what? I considered my options. I had a decent experience working with Unity ads on BuildDown, but they only support interstitials, and I wasn’t going to shoehorn that in at this stage in the game. I could try putting Admob ads on the iOS version, then all the platforms would be united under one ad network. But as I looked back over the data from the last few years, I noticed something interesting. Ad revenue has been falling for a long time:
It used to make up an about-equal component of revenue as IAP on iOS, and an even bigger piece of the pie on Android. But that had changed. Right as impressions were peaking:
Revenue per thousand impressions (RPM) fell though the floor:
Banner ads simply weren’t earning their keep, and hadn’t been for a long time. What was I doing, letting these things affect the user experience of my game for a pittance?
Meanwhile, in-app purchases were still holding their own. New people tried the game every day, and a respectable number were gracious enough to show their support with a mission pack or probe pack purchase. I decided to pull the plug on ads entirely, fully supporting the game on content alone. It would be the first time I’d released a game for profit without the cushion of advertising. And it would further cut the number of troublemaking plugins by one.
The unceasing march of technology
As one last shameful dig, Apple had slapped an embarrassing “<This App> May Slow Down Your iPhone (The developer of the app needs to update it to improve its compatibility)” warning on any apps that hadn’t been updated for 64-bit support. Yeah yeah, I got the message.
So there was my backlog, the must-fix operations. But there was another dimension to consider.
The update wasn’t just about removing problems. I wanted to add something, to give those folks that had supported the game over the years a reason to check back in and play the game anew. Removing ads and getting rid of crashes are important (critical, even), but they’re not exciting or inspiring.
The coolest thing I could add, of course, would be more content. Especially if I could include a new mechanic fans have been clamoring for since the beginning. I wanted to add the ability to land on the surface of an alien world. Immediately after making the requisite fixes, this was my top priority.
Additionally, I’d felt like the “Probe Variety Pack” was a bit thin on value. It was intended to be a cosmetic change only, and to be fair nobody ever complained about the purchase, but I wanted it to be more substantive. My answer was probe powers – unique abilities for each probe that change the way the game played. New Horizons, with the fastest launch speed of any probe in history, can launch up to 10% faster than other probes. Rosetta spent more than two years orbiting Comet 67P/Churyumov–Gerasimenko, what better craft to gain a gravity tractor bonus on the “disaster” levels Apophis and Comet ISON?
Speaking of those probes, a lot of science has happened since Voyager: Grand Tour launched in 2013. Rosetta’s entire comet-orbiting mission happened between the launch of Voyager and this update. Juno just reached Jupiter. And New Horizons breathtakingly fulfilled its mission, flying by Pluto on July 14, 2015. Those pictures were used to create the new, much more accurate surface texture for the planet.
Finally, even though the games are worlds apart, I wanted to do a little something to promote BuildDown within the Voyager community, a crossover of sorts. My wife suggested a tie-in spacecraft, the blockiest one there is: CubeSat. We’d learned a lot more about them over the last year – many of the countries we’d visited had only recently launched their first satellites thanks to the relative affordability and accessibility of CubeSats.
Just as Mariner 2 was a reward for rating the game, I could give away CubeSat just for trying BuildDown! I also added Hayabusa (which was originally intended for Voyager 1.0 but cut) and ExoMars (which both launched and reached Mars in 2016, and included a lander sub-mission, making it an ideal fit for the lander expansion). Both eventually became part of the BuildDown promotion.
I’m happy to report that I accomplished everything I set out to do on that list. Of course, there were compromises made in the name of scope. Lander levels are a new feature, not a new game, and might seem simplistic to the crew that landed Curiosity. But that replay of a probe settling onto the surface, mountains gaining depth and extending out over the horizon… definitely earns the mode its keep.
Finally, there were some things not on the backlog that came up during the project. While implementing the lander level replays, I made some adjustments that improved the replay experience even for standard flyby levels, like adding background stars and the Sun, and a tweak to the camera so that it aims for a good shot even from the night side of planets.
What Went Well
The biggest leg up I had was the sheer amount of groundwork I laid for this expansion that was simply waiting for me to capitalize on. I had art assets, bits and pieces of an object model, UI work in place… easily 10-15% of the foundation was ready from the word go. That made progress swift and rewarding, resulting in a positive feedback loop that made the work seem lighter.
Updating the project for the latest version of Unity and removing troublesome plugins was relatively pain-free. The code in this game isn’t quite as sophisticated as my recent projects – there were plenty of GetComponent calls everywhere after the project updater worked its magic, and I had to fix some obsolete API calls, and everything is still done through polling instead of being event-driven. Still, it worked fine on the newer version of the engine, and with fewer plugins to worry about, stability was good.
The asset I use for my planet shaders had preliminary support for planet tessellation, even in the version I was using three years ago, which was critical to implementing lander levels in a timely fashion.
My Path Predictor tool was especially useful for turning around a new set of levels quickly. It helped that I had a decent bank of ideas to try out, but it acted as an effective force multiplier for my design efforts, quickly providing feedback that made iterating on and honing in on fun and challenging missions incredibly fruitful.
It required only minor tinkering to get back up and running after several breaking changes (e.g. the object model, differences in the physics simulation). I feel that if Voyager were profitable enough to warrant full-time attention, it would not be that great of a leap to extend the tool with machine learning capability to further automate the generation of numerous and varied missions.
Finally, improving replays was an easy win. I already had everything I needed in the game: starfields, an aura effect for the sun’s corona, the camera images generated at runtime from the flight data. A few new planet textures, ramping up the camera noise, and an improved algorithm for calculating the camera look target made old replays look better than new in no time.
What Went Not-So-Well
That preliminary support for planet tessellation? It was very preliminary. I had the basic ability to define a heightmap a planet and a few knobs to tweak for scaling detail by distance and processor budget. The developer had wonderfully continued to support and advance the asset (I know, I still use it in another prototype), but over three years there were many breaking changes, and I simply couldn’t afford the risk of upgrading in this case. That meant I had to make difficult tradeoffs in order to get lander levels to work. Cloud layers were okay, but atmospheres had to go (so if you’re wondering why landing on Venus looks awesome but Earth’s sunsets look a little… missing, there you go).
Voyager’s camera is pretty neat, and is quite capable within the confines of the game. But, it was built very specifically for the needs of flyby levels. Landing is a different beast, and the hybrid I had to Frankenstein it into for the needs of those new levels is, at best, a hack. I love going back to old projects like this, because it reminds me
not to to think long and hard before I compromise on modularity and extensibility just to make something work.
Likewise, there were some assumptions built into the game, object model, etc that limited my choices in the expansion, preventing things like lander levels with moving targets, multiple-target disaster levels, and more. Sometimes constraint can be the mother of invention, and I like what ended up in the mission pack, but I’m not thrilled with the amount of good ideas left on the table because technical debt made their implementation infeasible.
There were also changes in physics engine between Unity 4 and 5 that just barely screwed up the simulation the game was built on. I ended up having to fudge the timing slightly to get it to behave as expected.
What Went Neutral
The UI package I used for Voyager was made obsolete by the engine’s “new” system (circa Unity 4.6), which I’ve used for all my subsequent projects. But the cost of retrofitting would be too great. What was there is a little clunkier than I remember, but more than good enough to get the job done. It helped that there wasn’t a ton of UI work involved in this update.
The unchanged Social API made it easier to keep in leaderboards and achievements on iOS than to take them out, but for all intents and purposes I consider them deprecated. The new level set does not support them, and I finally added an option to disable Game Center for those people that had no interest in it and were annoyed with dismissing the little popup every play session.
Rapid response, 2.0.1
On December 15th, Voyager 2.0 went live. After the frenzy to get it out onto the store, I had some time for more subtle issues to sink in. The new icon was too dark on my default (energy-saving) screen settings. The splash screen was a little wonky on iOS. There were minor bugs here and there that were missed before release.
I also wanted to work in some more feedback on the lander levels, and was able to turn around a solution – a combination speedometer/warning light – under the wire for submitting to the stores before the holiday break.
Three days later, 2.0.1 was live and I was finally done.
Bonus Android update, 2.0.1 (2)
Well, almost. While perusing reviews on both platforms, I noticed some of the early responses to the new version made reference to a continued problem with excessive permissions. The game was asking for permission to control the phone and make calls, which granted, seemed excessive. In any event, without ads in the game it wasn’t even required. I quickly issued a fix that removed this permission and all was right with the world.