Work Postmortem: SlideCity – Your First Game Will Be Hard

This is a postmortem written for a game I created for ADX Labs, LLC under the GameSmart brand as their employee.

This postmortem documents the decision making process that ultimately led to my first game being published at work.

At the time of writing, SlideCity has 2.5 million plays, and within the GameSmart platform is rated 4.8 out of 5 stars.

In August 2016, I was working between contracts and making pizzas to pay rent.  Chiefly, I worked on Iris Burning in my spare time, and my fiancee helped me by pruning through tons of job applications to help me get employed before it was time for me to start paying student loans back.  On August 8th, I received an invite for a phone interview with a company in Minneapolis specializing in mobile game development, and then proceeded to have the interview over Skype.  Within 48 hours I had an offer by phone, and began preparations to move to start work as a mobile games developer.

Starting Out

In September, I began working on games for the new job.

Upon initial arrival, the mobile games branch of the company was still fairly fresh, and the Android application frontend for delivering the games was still under development.  Due to this, the type of games I could develop was limited: work told me that while I was interviewed on the basis of Unity knowledge, I’d need to use a different, more browser-friendly game engine (Unity’s WebGL implementation was very mobile-browser-unfriendly at this stage).  Not a problem, I thought, the skills transfer between engines.

Initially, my boss pitched me a Match3 game to work on.  I wasn’t opposed to this; however, there was notably already 2-3 Match3 type games available on the website at the time, so I opted to try something different.  In the past I had developed an isometric game engine (unfinished, but able to place entities, generate terrains, and be otherwise workable), so I thought of perhaps doing something with that.  Obviously, being that it was written in Java at the time, it couldn’t be used for this game; however, I could lift the pseudocode and use it to roughly shape one out of JavaScript that would run natively in the browser, which I felt was a suitable compromise.

Sigtopolis, a SimCity 2000 clone attempt I toyed with a few years before GameSmart.

Just before this, a sale had taken place on Game Maker Studio Professional 1.4 through Humble Bundle, and I had picked it up–as had everyone else at work.  They also had been combing through examples to see what kind of games could be worked through Game Maker.  They had an isometric 2048 game prototype running with placeholder assets in the browser, and after seeing it in action, I decided that this would be the type of game I go with.  No one at the office was 100% familiar with Game Maker at that point, so I met little resistance in choosing to implement in JavaScript instead of working with GML since I had worked with JS in the past.

Weeks 1-3: Getting a workable game

I started by procuring a JavaScript-based HTML5 canvas handler.  The last time I’d had to develop my own, I used slick2d, a framework based on lwjgl, and I was hoping to find something with similar syntax, as slick2d is not really well maintained anymore and obviously wasn’t going to work in a browser.  I settled on EaselJS which handled rendering, sound, game states, and other such things quite readily.  I spent a few days of my first week or so (after the initial paperwork and IT hiccups) getting acquainted with EaselJS.

The next thing I looked at was to actually develop the game.

SlideCity’s EaselJS implementation rendering a grid using the math I learned doing Sigtopolis.

My boss opted to be the artist to help me out on the aesthetics of the game since I would be footing all of the programming work.  We settled on prerendered, 2D renderings of voxel-based graphics, in a cyberpunk Blade-Runner-esque urban environment, with some neon TRON-like influences as is popular in the high-tech-low-life look of the genre.  The buildings would represent the 2048 numbers, and would become increasingly tall and extravagant as each building leveled up.

I git inited the game under the name punkcity in reference to the cyberpunk influences of the art direction, and got to work mapping out how the game should work in terms of code.

An art test utilizing postprocessing done in Photoshop and voxel art by my supervisor.

Initially, we wanted a subway transit map type of overworld between levels and had each level work with one type of building that would get bigger little by little, in addition to later playing fields being larger than the base 4×4 grid in most 2048 implementations.  This worked in testing quite well until we started introducing the game to players who weren’t familiar with how it plays or how the art looked in context.  Players found it to be difficult to tell which buildings lined up with each other, making tight 4×4 grids quite hard to work with if you couldn’t distinguish the buildings.  This wasn’t the worst outcome, but it’s something I should have seen coming from the start.

The game functioned as a 2048 clone, but it was hard to tell what was what with similar buildings of varying heights.

Weeks 4-6: Cracks beginning to show

As with any solo developer’s first published game, things started to fall apart slightly at this point.

I was already self-conscious about the game taking more than 3 weeks to develop, which may prompt some eyebrow raises from readers: Three weeks isn’t much time to develop a game; there’s game jams that take place in that time frame.  Why be self conscious?  At the time, my coworkers had published one game each–games that I wasn’t involved in the development of–and even though they had a head start before I had started working there, I felt like I was the new kid on the block, something to prove, needing validation, and so forth.  This is the mobile industry, where fast turnaround and constant daily plays is required.  I needed to get it together!  Obviously as the youngest employee in the office, this kind of attitude was good motivation to start, but bad motivation to continue with as development progressed, as it became a cancer on my own self-outlook and ability to produce meaningful work in the timeframe given, as I became more and more disheartened with every issue that hit the game, every bug report that came back, and every “how’s progress?” checkup question I’d receive.

Now that I have been here a while, I know that week 4 is the time you should have a serviceable build for QA to look at and start picking apart, to see if the game works on its own.  By week 4, I had a play/win/lose/repeat feedback cycle.  Okay!  That’s progress.  But many key features were still missing, such as the energy-based monetization scheme, the entire GameSmart SDK integration (handling user save data, high scores, and anything involving our server backend), and proper level progression.  You could move between levels, but the UX of getting between them was very janky, very ‘programmer-centric,’ and certainly not ready for mass audiences.  I was spending nearly a day getting a single animated sprite implemented in the game for the overworld map, and given the timeframe these games are developed on, you should know that having issues like that isn’t good.

Working in a new environment certainly had part to do with it–I know how to do animated sprites and UI elements in Unity, but coming up with a way to serialize the data, load it on the fly, arrange it in the format expected by EaselJS, manage the playback of frames, and hide the sprite when not in use all took a ridiculous amount of time to develop cleanly, both because I was unfamiliar with Easel, but also because I learned JavaScript pre-JQuery, pre-ES5/ES6, when getElementByID() was the way to do things, none of this strange $('#selector') crap.

I tried to remain headstrong.  I became irritated with the way JavaScript does things.  Is it an object?  Is it a function?  Who knows! I remarked snarkily on social media in conversations about JavaScript game development.  I would spend time doing other, more feature-creepy tasks like developing animation for the title screen in After Effects (which did need to happen, just not at this stage).

What I should have done: admit that trivial tasks were taking longer than they should have in an engine I wasn’t familiar with, and seek out a better way.

What I did instead: stick to my guns and attempt to overcome.  It’s just a new engine, right?  Surely it’s just a hiccup of having used the same tech for the last few years and having to switch on short notice.

This pattern continued all the way up to week 7, where I came to realize the breaking point of punkcity as a native JavaScript game–rather, I should call it SlideCity, the name suggested around this time by a coworker, which it was eventually shipped under.

Week 7: “Test Like You’re a User, and Do It Early and Often” – Captain Hindsight

A word of advice from the horse’s mouth: Test the damn game the same way your users would play it.  Compile it.  Deploy it to a device.  Abuse it as much as you can.  Don’t do what I did here and wait nearly 2 months into development to see how the game plays.

I confidently packaged my game into a compact 11MB archive that the web team could upload to our dev server for testing.  It was time to see it in action!

We deploy our games to our platform by using Android WebView as a browser context (meaning Chrome/Chromium makes an excellent analog for testing), meaning testing in the browser directly also demonstrates roughly how the game will behave not only in our app, but for casual users perusing our website.  This means we can just pop open our web browser on our computers and smartphones and navigate to the internal dev website to see the games live for testing on the fly–after having the web team upload a build, of course.

For non-webview clients like just using Chrome to look at the website, this means an <iframe> is used to create the game context.

The game was designed on my 4K LG monitor provided by the IT department.

There was no scaling applied within EaselJS.  It was all scaled individually by the sprite.

If you can imagine playing a 4K game on a 1080×1920 portrait device like the ZenFone-based devices we had on hand, you can imagine how this would go.  Everything was tiny!

I tried everything to fix this issue.  I used CSS max-width and overflow properties to try and scale the canvas after rendering, but this caused a massive spike in CPU usage as EaselJS used fixed positioning and this meant that I’d have to draw the game natively, scale it down at the end of the game’s render step, and then scale it back to native again invisibly for the game logic to take place, repeated ad infinitum.  Certainly, a JavaScript 2048 game shouldn’t murder a phone battery, but mine did–if it didn’t just kill the framerate outright, that is.  I even tried applying a global scalar value to the coordinate system and sprite sizes, but this broke more things than it fixed, especially input events which expected touches to take place within the playing field, and coordinates wouldn’t come back correctly if inputs weren’t in the same plane as the scaled sprites.

The game was otherwise serviceable.  You could play, win, lose, switch levels, level up, expend energy by playing, recharge it by waiting (though the refill timer was not exposed to the end-user at this stage), and so on.  All of the things needed for a workable game.  But the scaling issue persisted.

At the end of it all, I just couldn’t get scaling to work correctly–not to mention getting the game to respond to fullscreen requests was another sub-problem related to this one that I had no idea how to begin addressing.  I tossed in the towel, feeling like a failure.  In spite of this, my boss reminded me that the Game Maker-based prototype still existed, and that I could try it out.  At this point, I felt like I had little to lose, so I jumped on it the second I could.

I was essentially starting over, eight weeks into development, and my coworkers were almost finished with their second games from the time I had started working there.  This didn’t bode well.  Nevertheless, there was not much choice here.  I still had something to prove.

Week 8-11: Acceptance & Adoption of Game Maker

For a Unity boy and estranged JavaScript user, Game Maker is a totally different world.

Its concept of object-orientedness is fleeting: don’t expect to get nice things like polymorphism, interfaces, or overrides in the traditional sense.  You’ll miss out on things like the ternary operator: condition ? operationIfTrue() : operationIfFalse().  In HTML5 deployed games, you have to render your text to a spritesheet: you can’t hook the browser’s text rendering features–irritating for games like ours that require translations in non-Latin languages, where the character sets are so massive and diverse that you’d need to know all of the text in the game before the game was finished.  It runs on its framerate and system time rather than a fixed timestep or a time delta like Unity or Unreal Engine. All of these things were sources of frustration, but all of it dwarfed in comparison to having a game that didn’t work.

You do have to do some extra work to get started, but the important thing here was that everything was working from the start.  Foundational issues like scaling weren’t a problem here, and that was all that mattered.

Despite much frustration, I altered the template significantly from its original form.  I put city streets in between the buildings, making it easier to distinguish which buildings are which level (and preventing tall buildings from totally occluding short ones, since isometric perspective dictates that height also indicates depth).  I integrated the SDK, though with a some hiccups here and there.  The testing phase only took about 2 weeks to complete before the game was considered production ready.  Bugs were related to gameplay and logic errors, not fundamental flaws in the core implementation.  I was home again, even if home meant working in a verbose world where array length is called upon with array_length_1d() instead of .length.

At the end of November, the game released finally.  I can’t speak specifics on how well it did sales-wise, but it performed well enough that I didn’t feel as bad about taking that much time to make it, especially for a first game.  But hot damn, was I glad to see that monster put behind me.  It was done and over with.  I was free, and I had a game out in the wild.

The game, as it stands, is one of my most-played published titles on GameSmart, despite being one of the most turbulent.

I did have to make some hotfixes after the fact, such as energy not recharging correctly at the right time, or Game Over text not appearing in the correct localization, but that’s typical fare compared to your entire game being an unusable hot mess on your first major beta.

Final Thoughts: Your First Game Will Suck (But That’s Okay)

Hear me out.  Even if you clone a known-fun gameplay paradigm like I did, there will be some degree of notable suckiness in your first game.  In my case, I should have made sure the game was rendering correctly in a smaller iframe, on a phone screen, deployed from a remote server.  I should have tested fullscreen functionality early on.  I should have checked on fundamental aspects like this likely to hurt me later, but I didn’t, due to a combination of pride and lack of experience.  I should have conceded earlier for my own sake and used the right tool for the right job.

Having said that, I have my own set of bones to pick with Game Maker’s syntax even coming from the cushy, loosely-typed world of JavaScript, but that’s better suited for its own post.

In the game I am currently working on for work as I write this, I attempted to use straight JavaScript again, and things were starting to go similarly within a week of starting, indicating to me that using another engine is still the way to go.  The difference is that I knew the signs, I’d seen it before, I knew when something was taking too long that it was time to stop beating around the bush and fix the things I have control over before it’s too late.

An important lesson in life to know is that a wise man knows when to admit he is wrong, and a foolish man doubles down.  Here, I learned the hard way.  I’m still learning–but that’s the important part of this line of work; if you don’t grow, you will never walk among the elite developers.