Never Burn Money

Discovery

Your project has been running for years. It’s been through so many hands that nobody understands the whole thing. It is just too big. But it’s also too big to start over, too much has been invested in it. Unfortunately, the code was not well designed and is just getting worse with each new desired feature. We made a coding standard for all new code going forward, so why is it that things seem to be getting worse and not better? How can we fix this mess of spagetti?

The reason nothing is getting better is that nobody knows where to start from when adding a new feature. The code is so large that when you want to add something new, you don’t know what to build it on top of. There are no layers of the original app, because it’s grown over with the vines of so many special cases that were added by the coders before you. So everyone reinvents the wheel each time, making the project even larger.

But all is not lost! There is still a path to redemption!

What is really wrong is an issue of discovery. The project is so big that nobody knows the ‘best practice’ for this project to do any given task. “I want to make a scrolling list of UI items.” There’s a whole lot of ways to do that, and because this project is so big, there’s lots of examples. But none of them do quite what you need, or it could be more efficient. So you make your own version which does it better. And the next person comes along and knows _nothing_ about what you wrote, so they do it all over again.

The solution is actually very simple: an index document that lists generic tasks and points to specific examples of code that solve those tasks. In the Index, you’d search for “scrolling list of UI”, and it points to an exact file that demonstrates that task. Or it could get even more specific, like “for a few elements” and “for many many elements” and “with group headers”, all pointing to different examples in the code. With each entry it lists a one sentence blurb that clarifies what makes that example different from the others in the category.

One of the bonuses of an index document is that it can be searched easily, as there should not be a large amount of content for each kind of task.

Homework

A couple months go by. There are finally some good examples of doing several things in the project. The index document is pretty stable these days. But the project is still getting bigger somehow. What’s going on here?

We’ve started creating these ‘clean’ examples, but nobody is making them re-usable! They’re only doing copypasta!

The failure is that the app is not being designed in layers. When a new feature is requested, the code is being copied from the template instead of refactoring the template to provide shared code for both the template and the new feature. New rule: to add a feature you must add a layer, not modify existing code. You can refactor existing code to make that new layer, as long as you support the original with its own layer on you refactored base.

This sounds like a heavy burden in such a large codebase, but that will only happen when first starting out. It should happen less and less often, once we start doing it in earnest. This is because the more layers we add, the less special cases will be needed.

RAM

So that fixes that. Right? Not quite. This entire process change is a new coding standard. And if we’re doing our job, the coding standard will continue to improve, covering new situations that we haven’t handled before. Now we have an index file that’s pointing at the old examples, which don’t match the new standard. It’s still a better situation than we started with, true. But how can we tell that the examples are all following the latest standard? We can’t.

Yet again, there is a simple solution to this problem too. We ‘version’ the standard. With human understandable numbers, like ‘2.0.’ As we update code to adhere to a new standard, we simply comment the source file with a header mentioning “Code Standard 2.0.” The rule would then be: if you don’t see a coding standard tag, you’re not allowed to use it. If you see a tag but it’s old, verify that it still meets the latest standard and update the tag.

For ‘core’ objects that is used by many things like UIController, one tag for the header isn’t really enough – instead it gets included in specific method definitions. The idea is the same.

We can even extend this to best practices in our prefabs! A simple single MonoBehavior component that stores an enum of a coding standard version. Along with the Note component for commenting, it will clearly identify that the GameObject and children of that hierarchy are correctly following a given standard, and is therefore safe to use as a starting point for a new UI or system.

And there we have it. A way to untangle the mess without losing your hair.

Efficiency in Complex Mobile User Interfaces

In freemium games, presentation is everything. The game itself can almost seem secondary to all the screens these games need. Your typical game has a couple menu screens for adjusting options, a main Heads Up Display that stays (fairly) consistent during your game, and that’s about it.

But this article is for the games that have an inventory to manage, a store to buy stuff from at any time, ‘on sale’ offers, custom game modes. And this isn’t limited to freemium either! We will be discussing in terms of the Unity3d game engine, most of the underlying concepts apply to any game engine, including home grown.

I’ve had some experience with this, where I learned someone else’s system. And this, where I built my own. Two, in fact, since there was a major redesign just before release. Oh, and this too. I’ve been designing and implementing user interfaces for games on desktop for twenty years, and since the original iPhone.

Users are fickle. This is not a bad thing – it is purely a thought to keep in mind. You might have a great game with thousands of players but scratch your head why nobody is willing to pay money in it. What is often overlooked is how easy or hard it is for the player to pay you! The player does not have a mental tally in their head about whether they want to pay you. It is emotional, not logical. They don’t keep a list of bullet points in their head: “Is this game snappy? Does it act the way I expect it to? Is it leaving a small memory footprint so I’m not looking at a loading screen after I get off this phonecall?”

Players just have a feeling that this is a “good game”. Your job as a developer is to lower the “barriers” between players and the game. But I didn’t come here to tell you how to design a freemium UI. I came here to keep you from tearing your hair out after realizing what not to do.

In games, user interfaces are typically an afterthought. “Check out this great game!” Press “New Game”, and you’re off. The typical coding style behind most game interfaces reflect this. You start with a single “New Game” button. Then you add an options menu. Now add the player’s bought gold on every screen. Oh, and we want to be able to buy stuff with that gold. Wait, how do we get the gold? Another store area! Pretty soon, you’ve got this gigantic, complicated code that reflects a gigantic, complicated user interface. But there is a better way!

We can instead borrow from the kind of thought that has gone into decades of desktop application user interface design. And the neat thing is, it boils down pretty simply, you need only to keep a few rules in mind while writing your code.

Just the basics, Ma’am

The first thing to remember is to make separate chunks out of what you present to the user. If you’re showing a counter of how much gold the player has, you should be using the same visual language onscreen in every location. Otherwise the player will get lost, looking for it! Likewise, you should use the same code to display it in every location. The shift in code organization is subtle but important. Instead of a screen manager class saying “set this text to the player’s gold count”, you should instead have a consistent block of UI that knows how to set its own gold count when it is given a player record. Why does this matter? Because two weeks later when you decide you want to show the count in red, but only when the player is out of money, you need to change it only in one place – the code for that block of UI. Not all over your codebase.

Inconsistent Visual Language

Inconsistent Visual Language;
Difficult to Update and Maintain
Simple and Easy

Simple to Update and Maintain

Another often made mistake is to make each block of UI know how to find the ‘source of truth’, typically requesting values from a singleton. Because you’re always going to have just one player, right? Then the boss says “Social gaming is the big thing now. We want to see them on a leaderboard with their details.” Well guess what – you have to rework all the places that use an internal ‘source of truth’ to be able to use an external one. More time wasted and complications created.

Now to consider the next level up. We have these chunks of interface. In the desktop world, you can fairly easily classify each application’s display based on what will be shown in it. A typical application has only one “window” for each document, and then “dialog windows” for asking more detailed questions, when needed. If you consider your game as a “document,” then you will only have one “window.” This means that your settings screen is actually a “dialog window”. Like a desktop dialog, the settings ask more detailed questions, eventually to close and put you back on your main “document,” the game.

This seems simple enough on the surface. Until it’s not. What do you do when the boss says “we want to offer a sale after playing for five minutes.” Who knows where the player might be at that point. They could be in the main game. Or the leaderboard. Or the store. Then I have to save what screen I was on before I showed the sale, and return to it when I’m done. Oh, and then I have to tell that to the store screen where to go back to after it finishes the sale. Sure hope I made these all some consistent superclass so I don’t have to know how to reopen each and every screen. How do we make the boss happy, and not go crazy working out where to put the player after they “close” the sale display?

The Navigation Stack

It sounds complicated, but this is where desktop UIs have solved it for us. It’s called a navigation stack. Every new screen is a new entry on top of the stack. In the desktop world, when you close one dialog, it re-shows the last item that was hidden when you opened the new one. You don’t even have to think about what it was you hid, you just “go back.” A simple concept, easy to implement, and saves you loads of trouble. In fact, on Android devices there is a requirement that you must always support the hardware “back” button. If you have a navigation stack, you always know exactly what you’re going “back” to.

In this day and age, everyone wants everything “now.” It amuses me to remember back when I started that computers were advertising “no wait states”. That is, they will go so fast that you will never have to wait for your computer ever again. So many years later and we’re still waiting.

Unfortunately, most user interfaces still presume everything happens instantly. In reality, loading takes time. And even if it is truly instant, animations by definition take time. Those little flourishes which bring life to your game have a habit of moving pieces of your interface to unexpected places when you presume things are ready instantly. Take that navigation stack for example. You start loading your settings screen, and at that moment it’s time to display an offer for the “Newest stupendest game piece that gives you 50% extra damage!” But you don’t want to show players offers while on the settings screen, you don’t want to be that intrusive. So what actually happens is both screens load and try to show themselves at the same time! Worse, who do we go “back” to?

There is another easy solution to this. When making changes, like showing a new screen or closing the one you’re on – make those changes instant. But wait, I just said nothing is instant?! Make your navigation stack instant by having the stack entries be completely separate from the actual onscreen displays. This way you can ‘instantly’ show a new screen and make reasonable logic decisions, no matter how long it takes to actually load or animate that new screen for the player. (For those of you playing at home, this makes the stack entries behave like “models” of the MVC pattern.)

Here we are going to put some pieces together and get an unexpected but highly useful result. You wanted that consistent “player gold” display on most of the screens of your game, right? Well, we don’t need every screen to have a copy of that, do we? Just leave it up for the next screen. But then how do we know the next screen wants it or not? Guess what – the navigation stack entry for the new screen knows. The new navigation stack entry has already been added because it is instant; it knows that it has to start loading and animating a new screen, and it knows if it needs the player gold displayed. So while one is animating in, it can animate away the piece it doesn’t need. The whole thing looks slick and smooth to the player, like you meant it that way.

Same Dog, New Tricks

You’ve made it this far. How about one more trick up the sleeve? There are always special cases in user interfaces. An example: a dialog offers a reward for connecting the game to a social media provider. If the player accepts, you want to take them to your normal screen that actually does the connecting. Okay, fairly obvious. But we really want to drive the idea home by flashing the buttons that actually do the connection, and only when it comes from this reward dialog.

One implementation would have the buttons look on the navigation stack to see if that reward offer was on the stack, and flash the buttons when it sees that. Fair – it would work. But then the connect dialog would need changes to know the offer dialog exists, and then embed custom animations that have nothing to do with the core purpose of the dialog, complicating later improvements.

But what if… each navigation entry could accept a list of commands to run after the dialog loads? Now the offer dialog pushes the connect dialog on the stack, and the registers a command for when the dialog is done loading and animating into view. Once hit, the offer dialog finds the buttons in the UI by searching for a special tagged object, and adds the flashing animation to those tags. With that, the connect dialog doesn’t need to know anything more about the offer dialog other than a simple string to let designers know that the offer dialog does some custom stuff, and needs to be considered when making changes.

There is so much that can be done to make your life easier when building your games. Even in the simplest ones, adhering to these guidelines will save you untold headaches in the future.

Unity3d Asset Bundles – Unloading

This article is part of a series. If you’d like to skip ahead, you can go to the master post that links to them all.
 

This room is a mess. I’m constantly getting after my kids to clean their rooms. Why? Because two days later they complain they can’t find one of their favorite toys! It’s not my job to track their toys. But it is my job to track my game’s memory. We can’t leave stuff lying around in memory, or it’s just going to fill up and crash.

Memory management is of supreme importance in mobile game development. And of high importance in any other platform as well. Your game must run forever! You can’t just leave the textures from three levels ago in memory. You have to make sure things get unloaded from memory. But at the same time you don’t want to accidentally unload something you’re still using.

Obviously you will be tracking and deleting your loaded levels and GameObjects. But also remember that the asset bundles themselves have some memory overhead. In fact, on some platforms, you can only have a maximum number of bundles open at a time. You have to clear them out or the app simply crashes!

 

It’s been a year in the making of this single blog entry. Originally I wanted to discuss the unloading of asset bundles, and I will get to that. But in the course of working on my latest project I realized just how deep the rabbit hole goes.

It turns out that knowing when and how to unload a bundle is more art than science. It’s very specific to how you plan on using your assets. Even different assets within the same game have different needs. Here I’m going to describe what Unity allows, but there will need to be a bonus post on how to recognize what assets belong in what category.

The first rule to remember is that a bundle won’t unload anything that’s been loaded until the bundle is closed. I can’t stress this enough! It is not handled the same way the assets built into the player are. Assets loaded via Resources.Load() will go away when they aren’t referenced anymore and you do a Resources.UnloadUnusedAssets(). Bundles don’t do this! They will not unload until the bundle is closed, even if the assets aren’t used anymore. This makes closing bundles absolutely critical to managing memory effectively.

 

Toward this end, Unity offers two modes of closing a bundle: a) where the contained assets are left in memory and b) where the contained assets are removed from memory. This sounds so simple, but it actually creates significant potential complication.

A naive approach would always use the unloading version, so that you keep open a bundle as long as you’re using any of the assets inside it. However, there are limits to the number of bundles you can have open on some platforms. So what do we do? We unload as early as we can. But even that has a catch – an asset that was left in memory won’t be re-used if the same bundle is reopened later. It will instead make a duplicate copy. So be sure you’re really done with it before closing it!

So where do we go from here? For now, I leave it as an exercise to the reader to work out what bundles you need to keep around and which ones are safe to unload early. Remember to consider how assets shared between two bundles are also distinctly affected by whether the requesting bundles can be unloaded or not.