The Good, the Bad & The Ugly
The Stack: What's it made of?
- Custom built ECS engine
- WebGL rendering via Pixi.js (opens new window)
- Embedded in a Vue.js (opens new window) application
- Tests via Cypress (opens new window)
- Win, Mac, Linux via Electron (opens new window) & Vue CLI Plugin Electron Builder (opens new window)
- Steam SDK integration via Greenworks (opens new window)
- iOS and Android app via Capacitor (opens new window)
- IAP via Cordova Purchase Plugin (opens new window)
- Ionic Appflow (opens new window) for iOS and Android builds
- Analytics via Firebase (opens new window)
- Highscore backend via Firebase Cloud Functions (opens new window)
- Shell scripts for release automation
The Good: One Codebase to Rule Them All
The Good: A Plethora of Plugins
The Good: Responsive Design
Thanks to CSS it's startlingly easy to deliver a game with a responsive design which works on 4k displays just as well as on an old iPhone. You have to design your game accordingly from the start, but the actual implementation is remarkably easy.
The Bad: Console Support
According to my research, getting an HTML5 game to consoles is possible but so much work (see this video (opens new window) about the CrossCode console port) that in most cases it's easier to just rewrite the game in Unity or Godot. This essentially is the deal breaker for me: I want to be able to publish my games to consoles. Mobile gaming is where the money is, but especially as an indie it's much easier to get a slice of the pie on PC and consoles than it is on mobile and not being able to somewhat comfortably do that is the main reason I'm making my next game with Godot.
The Bad: Native addons and SDKs
The Bad: Dependency Hell
The amount of unnecessary fiddling with platform-specific quirks and the countless ugly workarounds I had to find to make it all work together is mindboggling. The current state of my game is a fragile balance between versions of third-party code I can't reasonably change without everything falling apart. Every single time I update one plugin something else breaks and I'm leaving the goldilocks zone of compatibility.
The Bad: Performance
The performance is a double-edged sword: I was impressed with the performance I finally squeezed out of my game, especially on mobile. But it took quite a bit of optimization to get there, which is true for all games but much less so for games made in engines like Unity or Godot – but we'll see about that, come back in a year for another post and possibly another changed opinion.
The Ugly: Firebase Analytics vs Electron
And from here on out it gets ugly: I have spent way too much time these past few months working around limitations imposed by third-party tools and software. Because I wanted cross-platform analytics for my game and had opted for mobile ads via Google Admob and utilized Firestore and Cloud Functions for my highscore backend, I naturally chose to go with Firebase Analytics, which basically is Google Analytics v4.
Unfortunately, the http endpoint dubbed "Measurement Protocol" for v4 is not available yet, which forces you to use the SDK wrapper, which in turn does not play nice at all with Electron. The SDK only works in a web environment with the HTTP protocol, while Electron uses the file protocol or variations of it. You can imagine the ugly workaround I had to write to overcome this limitation – essentially switching protocols at runtime to trick the SDK into thinking it's used in a regular browser.
The Ugly: Mobile Ads
And while we're speaking of ads: I wanted to use rewarded ads for the mobile versions to allow for some easy extra cash flow through some little bonuses here and there – but boy oh boy was I mistaken. In the end I have spent weeks on a feature which I have since removed completely, replacing all rewarded ad placements with a consumable currency.
Apart from the fact that the implementation was not trivial at all, there are just so many things that can break. So many cryptic config files to get right. And when you finally get it all working ad serving limits are placed on your accounts left and right. I have had tens of thousands of ad requests and only a couple of hundreds of impressions to show for. Oh and did I mention it is borderline impossible to reach the Admob support?
The Ugly: Appflow vs Electron
My monorepo for Core Defense was a thing of beauty for a long time. Enter Appflow, a cloud build service for packaging mobile apps made with Capacitor. I love and still use that service – but it had trouble building for iOS with the Electron packages in my repository, leading to signing issues unless all references to Electron were removed. Ultimately I had to resort to creating a separate sub-package for the mobile versions, symlinking the source folder of the main package. I cringe every time I look at that repo since.
All in All: Room for Improvement
All jaded rants aside: I've built a successful game with a programming language I love and I've been massively aided by open source software and cool proprietary tools. But looking back at the overall experience and the missed opportunities I'm going to try new things going forward – as I mentioned before my next game (opens new window) will be made with Godot. I'm not expecting this to be the silver bullet, but at this point I'm really keen on trying a framework that was actually made for games instead of endlessly trying to use a wrench as a hammer. If you liked this post, consider bookmarking this blog and coming back in the future, or following me on Twitter (opens new window) for updates. Oh and do ping me there if you've got different experiences or opinions, I'd love to hear your story as well!