Static Batching for Dynamically Loaded Objects

From time to time, I’ve been trying to optimize the rendering of Academia. I’ve employed many techniques (here , here , and here) to promote dynamic batching already and it seems like they’re not enough. My hypothesis is that dynamic batching hogs the CPU when there are more objects to batch (like around 10k to 15k saved by batching). It’s time to look else where.

So I took a closer look on static batching. Static batching, as I’ve read, is faster than dynamic batching, but at the cost of more memory. We’re still below our memory budget so static batching is worth a try. It is also quite smart. I tried a simple scene that was statically batched, then I deactivated an object. The object became invisible, of course, but I was genuinely impressed. I thought the engine would create a new bigger mesh from all the combined mesh. As such, you can no longer update this big mesh. I’m glad I was wrong since this implies that I don’t have to code something like remembering the vertices of the object and update the UVs when an object becomes deactivated. I don’t have to change the existing game logic at all.

YuugeBatch
Majority of the objects in the game are non-moving

Static batching was already ticked in the Player Settings since ever, but when I run the frame debugger, I don’t see any static batching at all. Majority of the objects in the game were already set to static. I’ve been using Unity since 2011 and there are still stuff that I don’t fully understand. I’ve discovered that static batching does not work on dynamically loaded objects, which is how our game runs. It only works for objects that were baked in the scene and was set to static. For dynamically loaded objects, you have to manually call StaticBatchingUtility.Combine().

Gotchas

When I implemented the manager that will call StaticBatchingUtility.Combine()  strategically, the first issue I encountered was that you can’t update the UVs of the combined mesh. This means that if an object has UV manipulation like sprite animations, it cannot be added to the meshes to be combined. The engine throws an error if you manipulate the UV of a combined object. I had to filter out which objects can be combined. I used the StaticBatchingUtility.Combine()  method which accepts an array of GameObjects to be combined.

When I finished the static batching manager class, I thought everything will just work. When I run the game, still zero static batches. This brought me a lot of more trial and error and more headache that I almost gave up. When I was about to shut down, I read the documentation again and it said “The GameObject in gos must have MeshFilter components attached for this to work.” It was such a eureka moment. I usually prepare my game elements where the meshes or sprites are child GameObjects. I was combining the parent objects instead of the child objects that contains the MeshFilter. Don’t make this mistake.

Conclusion

In the end, I got to finally make it work. It saved me 1-2ms of rendering time. It’s not much but it proved that it is indeed faster. I’ve only implemented it in just one part of the game. There are still other parts where I could apply it.

That’s it for now. If you have unique rendering optimization techniques, please do share them.

 

Advertisements

Script to Play the Main Scene from Anywhere

This is related to the multiple scene development that I’ve described before. One of the problems I had was whenever I was working on a scene and had to test, I had to locate the Main scene, load it, then hit play. After testing, I have to load the scene that I was working on again. Sometimes I forget what scene that was. As you can imagine, this is really frustrating and can eat up time.

Fortunately with Unity, you can make scripts that can run in the editor. I made a script that loads the Main scene, and run it. When the game is stopped, the script loads the previous scene that I was working on. The script can be executed via a menu item or by pressing Alt + Shift + Z.

Here it is:

[InitializeOnLoad]
public static class RunUtils {

    static RunUtils() {
        EditorApplication.playmodeStateChanged += LoadLastOpenedScene;
    }

    // pref IDs
    private const string LAST_OPENED_SCENE = "Game.LastOpenedScene";
    private const string PLAYED_USING_RUN_UTILS = "Game.PlayedUsingRunUtils";

    // bool states
    private static bool aboutToRun = false;

    [MenuItem("Game/Run Game #&z")]
    public static void Run() {
        SceneSetup[] setups = EditorSceneManager.GetSceneManagerSetup();
        if (setups.Length > 0) {
            EditorPrefs.SetString(LAST_OPENED_SCENE, setups[0].path);
        }

        EditorPrefs.SetBool(PLAYED_USING_RUN_UTILS, true);
        aboutToRun = true;

        // Refresh first to cause compilation and include new assets
        AssetDatabase.Refresh();

        EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo();
        EditorSceneManager.OpenScene("Assets/Game/Scenes/Main.unity");
        EditorApplication.isPlaying = true;
    }

    private static void LoadLastOpenedScene() {
        if (EditorApplication.isPlaying || EditorApplication.isCompiling) {
            // changed to playing or compiling
            // no need to do anything
            return;
        }

        if (!EditorPrefs.GetBool(PLAYED_USING_RUN_UTILS)) {
            // this means that normal play mode might have been used
            return;
        }

        // We added this check because this method is still invoked while EditorApplication.isPlaying is false
        // We only load the last opened scene when the aboutToRun flag is "consumed"
        if (aboutToRun) {
            aboutToRun = false;
            return;
        }

        // at this point, the scene has stopped playing
        // so we load the last opened scene
        string lastScene = EditorPrefs.GetString(LAST_OPENED_SCENE);
        if (!string.IsNullOrEmpty(lastScene)) {
            EditorSceneManager.OpenScene(lastScene);
        }

        EditorPrefs.SetBool(PLAYED_USING_RUN_UTILS, false); // reset flag
    }

}

This is a fun little script. The key here is to register a delegate to the event EditorApplication.playmodeStateChanged which is called whenever the editor’s play state is changed (play, paused, or stopped). By using EditorPrefs, we can save some variables like LAST_OPENED_SCENE and PLAYED_USING_RUN_UTILS which we can access whenever the delegate is invoked. I used EditorPrefs rather than normal variables because I can’t guarantee how the editor keeps variables. I’m not sure if the values of variables are still around like say after recompilation.

Note also here that I call AssetDatabase.Refresh() before running the scene. This is because I prefer to turn off auto refresh (you can do this in Preferences). It’s annoying when the editor keeps compiling when your game is already too big. But without calling AssetDatabase.Refresh(), I might also forget to refresh the editor before running the game. By doing it this way, I ensure recompilation whenever I run the game and there was updated code.

Enjoy!

Simple Query System

While making games using multiple scene development, I always find the need to get some value or object that is provided by a system found in another scene. Like the signal system, I want a similar system where I could query values without knowing the type of the provider.

When I posted my signal system on Reddit, someone pointed me to this blog post which describes a similar system that solves the same problem. I have to admit, I think it’s the better way. What I liked about it is that the events are type safe even to its parameters. Refactoring this system would indeed be a lot better.

I thought about this and I realized that I could make a query system with the same goals in mind – type safety. I did make one and I think I’ll be using this to our game from now on. If you’re going to use this code, I have to warn you that it’s not that battle tested compared to an older query system that I’ve been using. So use it with caution.

Usage

I’ll start with how it would be used. There are three entities that interact with the system. These are the query request, query requester and the query provider. The requester and provider can be in the same scene or in different scenes. The query request is nothing more than a class that holds the parameters of the request. This is a sample request:

public class TestRequest : QueryRequest {

    private readonly int intParam;
    private readonly string stringParam;

    public TestRequest(int intParam, string stringParam) {
        this.intParam = intParam;
        this.stringParam = stringParam;
    }

    public int IntParam {
        get {
            return intParam;
        }
    }

    public string StringParam {
        get {
            return stringParam;
        }
    }

}

TestRequest here is an immutable class with two parameters. An actual game query request class may have more parameters.

Registration of the provider looks like this:

public class QueryManagerTestProvider : MonoBehaviour {

    private void Awake() {
        QueryManager.RegisterProvider<TestRequest, GameObject>(TestProvider);
    }

    private GameObject TestProvider(TestRequest request) {
        // Log the parameters just to show that they are passed
        Debug.Log("intParam: " + request.IntParam);
        Debug.Log("stringParam: " + request.StringParam);

        return this.gameObject;
    }

}

Providers are simply delegates so that they can be written easily. A single MonoBehaviour or class may register more than one providers.

A sample query request will look like this:

public class QueryManagerTestRequester : MonoBehaviour {

    private void Start() {
        GameObject result = QueryManager.Query<TestRequest, GameObject>(new TestRequest(77, "Hello Query Manager"));
        Debug.Log("result: " + result.gameObject.name);
    }

}

Putting them together will output this result:

QueryManagerResult

In my test, QueryManagerTestProvider and QueryManagerTestRequester are placed in different scenes so that I could verify that it works with such setup. Essentially, what I have done here is I was able to retrieve a GameObject that is from a different scene.

Framework Code

Let’s start with the base class QueryRequest:

public abstract class QueryRequest {
}

Yeah, that is it. It’s just used as a common type for all request classes. You can see it’s usage later. Why is it not an interface? The intent is for the user to make separate request classes that are lightweight. This prevents having big classes or MonoBehaviour classes that can also act as a query request.

Next is the QueryManagerImplementation class which will be the class that is used internally by the static class QueryManager. It looks like this:

class QueryManagerImplementation {

    private delegate object QueryProvider(QueryRequest request); // The internal delegate that we manage

    private Dictionary<Type, QueryProvider> providerMap = new Dictionary<Type, QueryProvider>();

    public QueryManagerImplementation() {
    }

    public void RegisterProvider<R, V>(QueryManager.QueryProvider<R, V> provider) where R : QueryRequest {
        Type type = typeof(R);
        Assertion.Assert(!this.providerMap.ContainsKey(type)); // Should not contain the provider for a certain request yet

        // Make the internal delegate which invokes the generic delegate
        QueryProvider internalProvider = delegate (QueryRequest request) {
            return provider((R)request);
        };
        this.providerMap[type] = internalProvider;
    }

    public bool HasProvider<R>() where R : QueryRequest {
        return this.providerMap.ContainsKey(typeof(R));
    }

    public V Query<R, V>(R request) where R : QueryRequest {
        Type type = typeof(R);

        // Invoke the provider
        // This will throw an error if a provider does not exist
        return (V)this.providerMap[type](request);
    }

}

Providers are simply maintained in a Dictionary where the key is the type of the request. The methods are self explanatory. The generic identifier R refers to the requester type and V refers to the type of the result value. Notice how QueryRequest is used here as a qualifier for R which limits what class types can be passed.

Finally, the static QueryManager class looks like this:

public static class QueryManager {

    public delegate V QueryProvider<R, V>(R request) where R : QueryRequest;

    private static readonly QueryManagerImplementation INTERNAL_MANAGER = new QueryManagerImplementation();

    public static void RegisterProvider<R, V>(QueryProvider<R, V> provider) where R : QueryRequest {
        INTERNAL_MANAGER.RegisterProvider(provider);
    }

    public static bool HasProvider<R>() where R : QueryRequest {
        return INTERNAL_MANAGER.HasProvider<R>();
    }

    public static V Query<R, V>(R request) where R : QueryRequest {
        return INTERNAL_MANAGER.Query<R, V>(request);
    }

}

Caveats

Like Signals, calling query requests are slower compared to just calling the provider method directly. Careful not to use it inside Update() or in parts where it is invoked repeatedly like in loops. Cache the results if you can.

Another disadvantage of this system is garbage. Every time you want to query for a value, you may instantiate a request class especially if it’s immutable. Although this can be mitigated by making a request class mutable and maintain only one instance of it then reuse that instance to make queries. Another way is to use the Factory design pattern for request instances.

This is it for now. See you next time.

Simple Signal System

In the last post about multiple scene development, I described a signal system briefly that we used for inter scene communication. This post will be about that system in full detail. I don’t claim that this is the best method. It works for us at the least but it can definitely be improved.

For objects in different scenes to communicate, I wanted something where objects don’t need to have the reference of the object in the other scene. I don’t want objects to have direct references of objects in another scene as much as possible (can’t completely be avoided). The rationale is that I wanted to avoid missing references when excluding loading of certain scenes at certain times. The game should still work even when some scenes don’t exist. I also wanted it to be simple and straightforward to use. This system will be exposed for software modding that we’re going to support later on.

Usage Sample

The gist of the system is that you have Signal instances which you can dispatch. Other parts of the game can then add listeners to a signal. When a signal is dispatched, the listeners will be executed. Parameters can also be added to a signal which can be queried by the listeners. Think of it as an observer pattern without a particular subject.

In our games, we maintain a static class where all game signals are collected:

public static class GameSignals {

    public static readonly Signal CLOSE_ALL_PANELS = new Signal("CloseAllPanels");

    public static readonly Signal HOUR_CHANGED = new Signal("HourChanged");
    public static readonly Signal DAY_CHANGED = new Signal("DayChanged");

    public static readonly Signal REQUEST_SCENE_TRANSITION = new Signal("RequestSceneTransition");

    ... // The rest of the other signals
}

Any component in any scene can add listeners to any of these signals. For example:

public class CashflowManager : MonoBehaviour {

    void Awake() {
        GameSignals.DAY_CHANGED.AddListener(ProcessCashflow);
    }

    void OnDestroy() {
        GameSignals.DAY_CHANGED.RemoveListener(ProcessCashflow);
    }

    private void ProcessCashflow(ISignalParameters parameters) {
        // Detailed cashflow processing implementation here
    }

}

During gameplay, one of the systems in the game (could be in any scene) will then dispatch the signal:

public class DayTimer : MonoBehaviour {
    void Update() {
        ... // Some code

        if(this.hour == 24) {
            // New day
            GameSignals.DAY_CHANGED.Dispatch();
        }

        ... // Some code
    }
}

Some signals require parameters. Dispatching signals with parameters looks like this:

Signal signal = GameSignals.ADD_FUNDS;
signal.ClearParameters();
signal.AddParameter(Params.VALUE, dailyCashflow);
signal.AddParameter(Params.ITEM, "CashFlow");
signal.Dispatch();

Implementation

Let’s start with parameters. Support for parameters is a must. Most of the time, it’s not used but you will definitely need them at times. Parameters are stored as string and object pair. The following is the interface for adding and getting parameters:

public interface ISignalParameters {

    void AddParameter(string key, object value);
    object GetParameter(string key);
    bool HasParameter(string key);

}

An implementation of this interface looks like this:

class ConcreteSignalParameters : ISignalParameters {

    private Stack<Dictionary<string, object>> parameterStack = new Stack<Dictionary<string, object>>();

    public ConcreteSignalParameters() {
    }

    public void AddParameter(string key, object value) {
        this.parameterStack.Peek()[key] = value;
    }
		
    public object GetParameter(string key) {
        return this.parameterStack.Peek()[key];
    }

    public bool HasParameter(string key) {
        return this.parameterStack.Peek().ContainsKey(key);
    }

    public void PushParameters() {
        this.parameterStack.Push(NewParameterMap());
    }

    public void PopParameters() {
        POOL.Recycle(this.parameterStack.Peek());
        this.parameterStack.Pop();
    }

    public bool HasParameters {
        get {
            return this.parameterStack.Count > 0;
        }
    }

    // Pool of parameter dictionaries
    private static readonly Pool<Dictionary<string, object>> POOL = new Pool<Dictionary<string, object>>();

    private static Dictionary<string, object> NewParameterMap() {
        Dictionary<string, object> newInstance = POOL.Request();
        newInstance.Clear();
        return newInstance;
    }

}

Parameters are stored in a Dictionary. Notice that we keep a pool of instances of these and there’s a stack manipulation involved. I’ll explain later.

The Signal class looks like this:

public class Signal {

    private readonly string name;
    private ConcreteSignalParameters parameters;

    public delegate void SignalListener(ISignalParameters parameters);
    private List<SignalListener> listenerList = new List<SignalListener>();

    public Signal(string name) {
        this.name = name;
        this.listenerList = new List<SignalListener>();
    }

    public void ClearParameters() {
        // Lazy initialize because most signals don't have parameters
        if (this.parameters == null) {
            this.parameters = new ConcreteSignalParameters();
        }

        this.parameters.PushParameters();
    }

    public void AddParameter(string key, object value) {
        // This will throw an error if ClearParameters() is not invoked prior to calling this method
        this.parameters.AddParameter(key, value);
    }

    public void AddListener(SignalListener listener) {
        this.listenerList.Add(listener);
    }

    public void RemoveListener(SignalListener listener) {
        this.listenerList.Remove(listener);
    }

    public void Dispatch() {
        try {
            if (this.listenerList.Count == 0) {
                Debug.LogWarning("There are no listeners to the signal: " + this.name);
            }

            for (int i = 0; i < this.listenerList.Count; ++i) {
                // invoke the listeners
                this.listenerList[i](this.parameters); // note that the parameters passed may be null if there was none specified
            }
        } finally {
            // Pop parameters for every Dispatch
            // We check if there was indeed parameters because there are signals that are dispatched without parameters
            if (this.parameters != null && this.parameters.HasParameters) {
                this.parameters.PopParameters();
            }
        }
    }

    public string Name {
        get {
            return name;
        }
    }

}

The Signal class keeps track of parameters and the list of listeners. Listeners are simply implemented as delegates that accept ISignalParameters. I specifically chose delegates so that listeners are easier to write. One could just write a method and that can be used already. A component may also listen to multiple signals. The listeners could just be different methods within the component. If it were implemented as an interface, writing listeners would be more tedious.

The Dispatch() method simply invokes all listeners then pops the parameters.

Why the usage of stack in ConcreteSignalParameters?

The old implementation of this class only maintains one instance of parameter dictionary. Unfortunately, this causes a bug when a listener of a signal dispatches the same signal again with new set of parameters. When this happens, the next listeners will use the new parameters instead of the original ones. We needed a way to somehow store parameters before dispatching the same signal. Thus, the usage of stack that you see here. The assumption here is Signal.ClearParameters() should always be invoked prior to Signal.AddParameter(). A new parameter dictionary is pushed whenever ClearParameters() is called. A parameter dictionary is popped in every Dispatch(). This is also the reason why we used an interface when passing parameters to listeners. Listeners need not know about the stack manipulation of parameters.

When to use?

This system is obviously less efficient than calling a method directly. We only use this for things that are not required to run every frame. This can be mitigated by moving objects to their proper scene. For example, if an object requires a reference from another scene for its Update(), maybe that object should belong to that scene. If this is not possible, then we may need that reference of the object from another scene. One can use GameObject.Find() but I try to avoid that approach. We use another system for querying objects/values which will be a topic for another day.

Multi Scene Development in Unity

Modern image processing software like Photoshop have this concept called “layers” in which the user can compartmentalize different parts of the whole image using this construct. Scenes in Unity can also be thought of as layers. Each can be developed separately but they can be combined together to form the whole game. Over the years of using Unity, I have been using this concept to develop my games.

Engine design wise, I think “scene” is a wrong term. It’s because a scene denotes something visual, something you can see, or something tangible. Intuitively, a user would think that a scene is for visible objects with their physics settings. Essentially though, a scene is a container of GameObjects. In this sense, a scene could contain only non visible stuff like game managers and data managers. A scene could contain only cameras, or only UI. What this means is you can make separate scenes for your game world, game logic, cameras, and various UI panels. When the game is run, you can additively load these scenes together which collectively makes up the whole game.

The Basics

Let’s say you have two scenes – “GameWorld” and “GameHud”. It’s a good idea to make another scene which is responsible for loading the other scenes additively. Usually this is called the “Main” or “Startup” scene. Whenever you want to run the game, you play this Main scene instead. This scene has a component that looks like this:

using UnityEngine.SceneManagement;
... // Other using statements

class Main : MonoBehaviour {
    void Awake() {
        LoadSceneAdditively("GameWorld");
        LoadSceneAdditively("GameHud");
    }

    private static void LoadSceneAdditively(string sceneName) {
        SceneManager.LoadScene(sceneName, LoadSceneMode.Additive);
    }
}

Why do it this way?

I have three main reasons – better organization, better work delegation, improves maintainability.

Better Organization

For example, I always make a separate scene for the system that handle audio. I have a separate scene for the system that handles persistence (saving and loading). Game static data management is contained in its separate scene. I can manage the different domains of game elements in their respective scene. Like in Academia, each handling of character types is its own scene.

Sometimes, it’s reasonable to put usage of third party software in a separate scene. If the game is level based (Level 1, Level 2, etc), each level can be a separate scene. Each UI panel or screen can be its own scene. A game feature can be its own scene. You open up many ways to organize your game.

Better Work Delegation

Now that the game is structured into multiple scenes, it becomes easier to assign work to team mates. You can assign someone to work on particular scenes or tell them to add a new scene (if it’s a new feature). An obvious example is to distribute work among different UI panels or screens. Doing it this way also reduces collaboration conflict. You can design your development such that artists and designers edit only certain scenes while programmers also work on their logic only scenes. It’s also now easier to know who’s fault it is when the game breaks. Just ask who owns the scene.

Improves Maintainability

Maintainability is very important to me. It’s that one thing that a software project has that allows it to be shipped. By separating domains in different scenes, the areas of where to fix or where to update becomes more clear. A new feature now means a new scene. Scenes that work well can be forgotten. This means more space for your mind to focus on more important things. You can also think of scenes as another way to refactor your game. You can split up a big scene or merge smaller scenes.

SomeScenes
Just some of our scenes

How do you render different scenes into one display?

You use multiple cameras. You can check this awesome post. This is the reason why I maintain cameras in a separate scene. In every game, I maintain at least two cameras, one for the game world, the other for UI.

How do scenes communicate?

There are lots of ways to do this. Personally, I prefer something that does not require a hard reference of some class or component. We use a signal system to signal something and interested parties will then do something. Kind of like a glorified observer pattern. We also use a query system. It’s like a signal system, but it returns a value. There are times when a program in a scene requires a value from another scene. We use this query system to get that value without requiring the reference of the provider. I’d like to delve into details, but this post is getting longer. So maybe in another post.

Taking it Further

Instead of hardcoding the scenes to load like I showed in the Basics part, you can make something like an XML or JSON config for this. Every time there’s a new scene to load, you just add that scene to this file.

In our system, I designed something called “Load Profiles”. Basically, we maintain different profiles of loading scenes. For example, there’s a profile for loading the complete game, then there’s another profile that loads the game directly to gameplay which is used for testing. This can also be used to load different scenes for different platforms.

You can design different patterns on how you load your scenes depending on your needs. This is it for now. See you next time.

 

Better C# Enums

I hate C#’s enum type. I avoid it if I can. Consider this example of an enum of planets:

public enum Planet {
    MERCURY,
    VENUS,
    EARTH,
    MARS,
    JUPITER,
    SATURN,
    URANUS,
    NEPTUNE,
    PLUTO // Pluto is a planet!!!
}

This is good enough to use for a while until a need arises to get the mass of a planet. So we do something like this:

// Returns the mass of the planet in 10^24 kg
public float GetMass(Planet planet) {
    switch(planet) {
        case Planet.MERCURY:
            return 0.330;

        case Planet.VENUS:
            return 4.87f;

        case Planet.EARTH:
            return 5.97f;

        ...

        case Planet.PLUTO:
            return 0.0146f;
    }
}

How about planet diameter? Another switch statement? What about for density? Gravity? Escape velocity? Just think about the amount of switch statements that you’re going to maintain. You can argue that you can use a Dictionary instead but that is still clunky. A Dictionary mapping per data? No way.

There is a better way and I’ll show you how. This may already be common knowledge among non Unity programmers but I’d like to put up this redundant topic again in my blog for such people who may not know this, especially beginners. I would also like to keep it simple. There will be no need for reflection in my examples. There’s also no inheritance.

Basically, you can use a class as an enum. Why a class? It’s just better. You can store any number of arbitrary data. You can even store a routine or a function. You can do a lot with it. The only requirement is that it should be immutable, which means that the state of an instance of the class cannot change throughout the duration of the program. Here’s a version of the Planet enum as a class:

    public class Planet {
        // The different values
        public static readonly Planet MERCURY = new Planet(0, 0.330f, 4879, 5427, 3.7f);
        public static readonly Planet VENUS = new Planet(1, 4.87f, 12104, 5243, 8.9f);
        public static readonly Planet EARTH = new Planet(2, 5.97f, 12756, 5514, 9.8f);
        public static readonly Planet MARS = new Planet(3, 0.642f, 6792, 3933, 3.7f);
        public static readonly Planet JUPITER = new Planet(4, 1898.0f, 142984, 1326, 23.1f);
        public static readonly Planet SATURN = new Planet(5, 568.0f, 120536, 687, 9.0f);
        public static readonly Planet URANUS = new Planet(6, 86.8f, 51118, 1271, 8.7f);
        public static readonly Planet NEPTUNE = new Planet(7, 102.0f, 49528, 1638, 11.0f);
        public static readonly Planet PLUTO = new Planet(8, 0.0146f, 2370, 2095, 0.7f);

        // Use readonly to maintain immutability
        private readonly int id;
        private readonly float mass; // in 10^24 kg
        private readonly int diameter; // in km
        private readonly int density; // in kg/m^3
        private readonly float gravity; // in m/s^2

        // We use a private constructor because this should not be instantiated
        // anywhere else.
        private Planet(int id, float mass, int diameter, int density, float gravity) {
            this.id = id;
            this.mass = mass;
            this.diameter = diameter;
            this.density = density;
            this.gravity = gravity;
        }

        public int Id {
            get {
                return id;
            }
        }

        public float Mass {
            get {
                return mass;
            }
        }

        public int Diameter {
            get {
                return diameter;
            }
        }

        public int Density {
            get {
                return density;
            }
        }

        public float Gravity {
            get {
                return gravity;
            }
        }
    }

To maintain immutability, all member variables should be readonly. Once they are assigned, they can no longer be changed. This is important because as an enum, it’s internal values should not change. Each enum value is then implemented as a static readonly instance of the class.

How is this used? It’s the same with normal enum but there’s more:

// Use it like an enum
ship.TargetPlanet = Planet.NEPTUNE;

// Want to know the target planet's mass?
float mass = ship.TargetPlanet.Mass;

// Density?
int density = ship.TargetPlanet.Density;

We have eliminated the need for switch statements or dictionaries to maintain the different planets’ information. Want a new planet stat? Just add a new member variable and specify them on instantiation.

How about conversion from other data types? Like say convert from int id to Planet instance? This is easy. Usually I add a public and static method for these conversions. For example:

public class Planet {

    // The different values
    public static readonly Planet MERCURY = new Planet(0, 0.330f, 4879, 5427, 3.7f);
    public static readonly Planet VENUS = new Planet(1, 4.87f, 12104, 5243, 8.9f);
    public static readonly Planet EARTH = new Planet(2, 5.97f, 12756, 5514, 9.8f);
    public static readonly Planet MARS = new Planet(3, 0.642f, 6792, 3933, 3.7f);
    public static readonly Planet JUPITER = new Planet(4, 1898.0f, 142984, 1326, 23.1f);
    public static readonly Planet SATURN = new Planet(5, 568.0f, 120536, 687, 9.0f);
    public static readonly Planet URANUS = new Planet(6, 86.8f, 51118, 1271, 8.7f);
    public static readonly Planet NEPTUNE = new Planet(7, 102.0f, 49528, 1638, 11.0f);
    public static readonly Planet PLUTO = new Planet(8, 0.0146f, 2370, 2095, 0.7f);

    // This can be used to loop through all planets
    public static Planet[] ALL = new Planet[] {
        MERCURY, VENUS, EARTH, MARS, JUPITER, SATURN, URANUS, NEPTUNE, PLUTO
    };

    // Converts the specified id to a Planet instance
    public static Planet Convert(int id) {
        for(int i = 0; i < ALL.Length; ++i) {
            if(ALL[i].Id == id) {
                return ALL[i];
            }
        }

        // return ALL[id] could also work here but what if a non sequential id is used?

        throw new Exception("Cannot convert {0} to a Planet.".FormatWith(id));
    }

    ...
}

// Usage
Planet planet = Planet.Convert(someIntPlanet);

Want to convert from a string id? Add a string member variable that will hold this value. Instead of using an array such as ALL[], you can use a Dictionary like this:

private static Dictionary<string, Planet> ALL = new Dictionary<string, Planet>() {
    { MERCURY.TextId, MERCURY },
    { VENUS.TextId, VENUS },
    { EARTH.TextId, EARTH },
    ...
    { PLUTO.TextId, PLUTO },
};

// Converts the specified string to a Planet instance
public static Planet Convert(string id) {
    return ALL[id];
}

You can support any type of conversion that you like.

There’s so much more you can do. You can now add functions. You can do something like this:

Planet currentPlanet = Planet.VENUS;
currentPlanet.ApplyGravity(ship);

The coolest thing for me is you can specify different actions or behavior to the enum values. Something like this (It’s very contrived but you get the idea.):

public static readonly Planet EARTH = new Planet(2, 5.97f, 12756, 5514, 9.8f, delegate(Ship ship) {
    // Actions on land of ship
    ship.AddFood(1000);
    ship.RetireCrew();
    ship.RecruitNewCrew();
});

public static readonly Planet MARS = new Planet(3, 0.642f, 6792, 3933, 3.7f, delegate(Ship ship) {
    // Actions on land of ship
    ship.DeductFood(50);
    ship.Research();
    ship.Mine();
});

By simply turning your enum into a class, you’ve upgraded it to something more organized yet also more feature packed. You could also use advance features like reflection and inheritance, but most of the time, you don’t need to.

That’s it for now. Hope this helps.

Unity Game Considerations for Modding Support

Last week, I began working on modding support for Academia. I have to pause development at least this week in lieu of bug fixing. I have vastly underestimated the amount of initial work that I have to do to make it work. For this post, I would like to add to the very few resources of this topic and hopefully help others prepare their Unity game better.

From the very beginning, we have decided to include modding support. It’s important to make this decision before making the game as it will affect the implementation details. In our case, we used StreamingAssets to load our images and text data in the game. What this means is we load the assets as if they are external files. The assets are not packed in Unity’s own format when the game is built. The files of these assets remain as is and are contained in the StreamingAssets folder. The reason for doing this is we want to be able to load files in other folders that would be specified by modders.

As a lesson, your game should be able to load assets in other folders, not just in StreamingAssets. I had this assumption that mod files from Steam Workshop could be downloaded to the StreamingAssets folder and I can load it from there. Nope! Steam downloads the mod files from Steam Workshop into folders that are maintained in the Steam library folder. The mod folder is usually in {Steam Library}/{Steam Game ID}/{Workshop ID}. Because of this, your game should be able to accept a different folder and load assets in that specified folder. For example:

// Instead of this:
private Texture2D Load(string assetPath) {
    string fullPath = Path.Combine(Application.streamingAssetsPath, assetPath);
    ...
}

// Use something like this
private Texture2D Load(string baseFolder, string assetPath) {
    string fullPath = Path.Combine(baseFolder, assetPath);
    ...
}

// Use it like this to load assets from Application.streamingAssetsPath
Texture2D texture = Load(Application.streamingAssetsPath, "SomeSprite.png");

In other words, your asset management system should be flexible enough to load other folders.

Another difficulty I had is the implementation of the Steam Workshop API itself. We are using Steamworks.NET to interface with Steam. While the Steam Workshop API is readily available with it, it’s not that easy to understand. You still have to wrap the API calls to make it manageable for your use. This could take days to make. To save time, I bought an asset, instead. While I didn’t like its predefined prefabs (which is how you use the asset), I did use its wrapper class for querying workshop items and downloading them.

The next challenge I had is the mod installation management. I wanted players to be able to install and stack multiple mods. This meant that I needed to have some kind of internal mods database and provide a UI for it. Implementation of this thing took the whole week.

ModsManagement

Aside from this, a system for testing/uploading/updating mods would also be needed. I plan to add this system as a tab to this screen. Loading assets from any folder would be valuable here. I imagine that the mod developer can specify the full path to his/her mod folder. Then he/she can subscribe to this local folder so he/she can test his/her creation. There will also be buttons for uploading/updating the mod. This is why I had to stop because it may take up the whole week again and I still have lots of bugs to fix.

There you have it. These are the considerations that I had thought while implementing the mod support. Hope these will help you on yours.

SampleMod
Simple mods that I installed. Blue characters and some graffiti on those kitchen sinks.

A Simple Mesh Combiner

Character meshes in our game Academia are always the hardest to optimize. There are many of them and they hardly batch even if I had combined all character sprites in one single texture. A character in the game has two quads, the body and the head. I had given up on batching multiple characters but what frustrated me is that these two meshes are always rendered in separate draw calls. This is because the head sprite has transparency and it should be rendered on top of the body sprite. The two can’t be batched. What’s a motivated guy got to do? I combined them into a single mesh.

CombinedMesh
On the left is the original face and body quads. The right one is the combined.

It’s easy to combine meshes. There are already existing tools out there for this purpose. However, I wanted something different. I want to be able to change the UV coordinates of some parts of the combined mesh during runtime. For example, when the character blinks, I want to change the UV coordinates of the face quad. I also wanted it to be lightweight. There are asset products like Mesh Baker that I find too bloated for my needs.

Time for some code! Here’s the MeshPartHandle. It handles the minimal data to represent a “part” of the combined mesh. It just contains a starting index and the vertex count of the mesh part. I’ll show the usage later.

    public class MeshPartHandle {

        private int startIndex;
        private readonly int vertexCount;

        public MeshPartHandle(int vertexCount) {
            this.vertexCount = vertexCount;
        }

        public int VertexCount {
            get {
                return vertexCount;
            }
        }

        public int StartIndex {
            get {
                return startIndex;
            }

            set {
                startIndex = value;
            }
        }

    }

The following is the mesh combiner itself:

    [RequireComponent(typeof(MeshFilter))]
    [RequireComponent(typeof(MeshRenderer))]
    public class CombinedMesh : MonoBehaviour {

        private Mesh mesh;
        private MeshFilter meshFilter;
        private MeshRenderer meshRenderer;

        private readonly Dictionary<Transform, Mesh> meshMap = new Dictionary<Transform, Mesh>();

        private readonly Dictionary<Transform, MeshPartHandle> handleMap = new Dictionary<Transform, MeshPartHandle>();

        private Transform selfTransform;

        public void Clear() {
            this.meshMap.Clear();
            this.handleMap.Clear();
        }

        public MeshPartHandle Add(Transform owner, Mesh mesh) {
            Assertion.Assert(!this.meshMap.ContainsKey(owner)); // Should not contain the specified owner yet

            this.meshMap[owner] = mesh;

            MeshPartHandle handle = new MeshPartHandle(mesh.vertices.Length);
            this.handleMap[owner] = handle;

            return handle;
        }

        private List<Vector3> vertices = new List<Vector3>();
        private List<Color> colors = new List<Color>();
        private List<Vector3> normals = new List<Vector3>();
        private List<Vector2> uvs = new List<Vector2>();
        private List<Vector2> uvs2 = new List<Vector2>();
        private List<int> triangles = new List<int>();

        // Cache array so we could easily set new UV values
        private Vector2[] uvArray;
        private Vector2[] uv2Array;

        public void Build() {
            this.vertices.Clear();
            this.colors.Clear();
            this.normals.Clear();
            this.uvs.Clear();
            this.uvs2.Clear();
            this.triangles.Clear();

            foreach (KeyValuePair<Transform, Mesh> entry in this.meshMap) {
                AddToBuild(entry.Key, entry.Value);
            }

            this.mesh = new Mesh();
            this.mesh.vertices = this.vertices.ToArray();
            this.mesh.colors = this.colors.ToArray();
            this.mesh.triangles = this.triangles.ToArray();
            this.mesh.normals = this.normals.ToArray();

            this.uvArray = this.uvs.ToArray();
            this.mesh.uv = this.uvArray;

            this.uv2Array = this.uvs2.ToArray();
            this.mesh.uv2 = this.uv2Array;

            this.meshFilter = GetComponent<MeshFilter>();
            Assertion.AssertNotNull(this.meshFilter);
            this.meshFilter.mesh = this.mesh;

            this.meshRenderer = GetComponent<MeshRenderer>();
            Assertion.AssertNotNull(this.meshRenderer);
        }

        private void AddToBuild(Transform owner, Mesh mesh) {
            MeshPartHandle handle = this.handleMap[owner];
            handle.StartIndex = this.vertices.Count;

            this.colors.AddRange(mesh.colors);
            this.normals.AddRange(mesh.normals);
            this.uvs.AddRange(mesh.uv);

            // Special case for UV2
            // Other meshes don't have it so we use zeroes
            if(mesh.uv2.Length == 0) {
                for(int i = 0; i < mesh.vertices.Length; ++i) {
                    this.uvs2.Add(VectorUtils.ZERO_2D);
                }
            } else {
                Assertion.Assert(mesh.uv.Length == mesh.uv2.Length);
                this.uvs2.AddRange(mesh.uv2);
            }

            // Adjust the triangle indeces
            for(int i = 0; i < mesh.triangles.Length; ++i) {
                this.triangles.Add(mesh.triangles[i] + handle.StartIndex);
            }

            if(this.selfTransform == null) {
                this.selfTransform = this.transform; // Cache
            }

            // Transform the vertices from its owner
            for(int i = 0; i < mesh.vertices.Length; ++i) {
                Vector3 transformedVertex = this.selfTransform.InverseTransformPoint(owner.TransformPoint(mesh.vertices[i]));
                this.vertices.Add(transformedVertex);
            }
        }

        public void SetMaterial(Material material) {
            this.meshRenderer.material = material;
        }

        public void SetSortingLayer(string sortingLayerName) {
            this.meshRenderer.sortingLayerName = sortingLayerName;
        }

        public void SetUvs(MeshPartHandle handle, Vector2[] uvs) {
            for(int i = 0; i < handle.VertexCount; ++i) {
                this.uvArray[handle.StartIndex + i] = uvs[i];
            }
            this.meshFilter.mesh.uv = this.uvArray;
        }

        public void SetUvs2(MeshPartHandle handle, Vector2[] uvs) {
            for (int i = 0; i < handle.VertexCount; ++i) {
                this.uv2Array[handle.StartIndex + i] = uvs[i];
            }
            this.meshFilter.mesh.uv2 = this.uv2Array;
        }

        public Transform SelfTransform {
            get {
                if(this.selfTransform == null) {
                    this.selfTransform = this.transform;
                }

                return selfTransform;
            }
        }

    }

This is then how it is used:

CombinedMesh combinedMesh = GetComponent<CombinedMesh>(); // Or any other way of getting this instance
MeshPartHandle headHandle = combinedMesh.Add(this.transform, this.headMesh);
MeshPartHandle bodyHandle = combinedMesh.Add(this.transform, this.bodyMesh);
combinedMesh.Build(); // Builds the combined mesh

// During gameplay, say we want the character to use the sprite that's facing left
Vector2[] leftHeadUvs = GetUvs("Head", Orientation.LEFT);
combinedMesh.SetUvs(headHandle, leftHeadUvs);

Vector2[] leftBodyUvs = GetUvs("Body", Orientation.LEFT);
combinedMesh.SetUvs(bodyHandle, leftBodyUvs);

The combiner class is very straightforward. It just maintains a list of mesh data like vertices, colors, triangle indeces, normals, and UVs. Whenever a mesh is added through CombinedMesh.Add(), we also add the data of that mesh to the locally maintained lists. Each MeshPartHandle remembers how many vertices it has and where its starting index is. The handles are then used to change the parts of the mesh it represents. For now, it can only change UVs. It’s certainly possible to allow changes to colors, or normals, etc.

By using this, Unity now renders a character in a single draw call. An added effect to this is that batching multiple characters is now possible in certain conditions. For example, characters that lie in the same horizontal line can now be batched.

CharacterBatch
From the frame debugger

This is just one use. I think I’m going to use this to combine other objects. Our rendering is still terrible. Here’s hoping that I can improve it by using this simple mesh combiner.

Reducing Draw Calls Using a Simple Texture Packer

When we started making Academia, we didn’t really plan out how are we going to manage our sprites. We just did the quickest way which was to make them individually and load them in the game. All of our game world sprites are stored in StreamingAssets. We load them dynamically when the game is run. This is different from the normal way using an imported texture. We did it this way in preparation for modding support. I envision that modders could then add their own folders and provide them the mechanism to override the base game images.

Ideally, all game sprites should be in a single big texture. This will allow you to use a common material throughout your game objects so that dynamic batching can indeed batch. Now that the game got bigger, it’s harder to put all of our sprites in one single atlas. Our artist wouldn’t agree to this as it’s a lot of work. Additionally, we no longer have the time. We’re releasing our Early Access this September 8.

SomeObjects
A few samples of our sprites. We have folders of these.

While coming up with solutions, I thought what if I could pack the images dynamically instead and use the generated atlas. It should be simple enough to recompute the UVs of the packed sprites. I scrounged the internet on algorithms on how to optimally pack rectangles in a bigger one. Turns out that this is an interesting problem. There are numerous papers about this. It also turned out that I no longer have to roll up my own packer. Unity already made one.

It needs some help, though. I needed something that keeps track of the packed textures. I needed a way to get the same sprite out of the packed one. Time to code!

Here’s the class that abstracts an “entry” of a packed texture:

    public class PackedTextureEntry {

        private readonly Texture2D atlas;
        private readonly Rect uvRect;
        private readonly Rect spriteRect;
        private readonly Sprite sprite;

        public PackedTextureEntry(Texture2D atlas, Rect uvRect) {
            this.atlas = atlas;
            this.uvRect = uvRect;
            this.spriteRect = new Rect(this.uvRect.x * this.atlas.width, this.uvRect.y * this.atlas.height,
                this.uvRect.width * this.atlas.width, this.uvRect.height * this.atlas.height);
            this.sprite = Sprite.Create(this.atlas, this.spriteRect, new Vector2(0.5f, 0.5f), 768);
        }

        public Texture2D Atlas {
            get {
                return atlas;
            }
        }

        public Rect UvRect {
            get {
                return uvRect;
            }
        }

        public Rect SpriteRect {
            get {
                return spriteRect;
            }
        }

        public Sprite Sprite {
            get {
                return sprite;
            }
        }

        public Sprite CreateSprite(Vector2 pivot) {
            return Sprite.Create(this.atlas, this.spriteRect, pivot, 768);
        }

    }

Basically, it’s just a container of the generated atlas and the UV coordinates of a particular sprite entry. The Rect passed in the constructor is a normalized UV (values are zero to one). Sprites, however, are created using pixels. So we need a new Rect for this which is just the UV rect multiplied by the dimensions of the atlas. This class also has a pre-generated Sprite pivoted at the center.

The following class is the texture packer itself:

    public class TexturePacker {

        // Contains the associated names of the added texture so we can easily query its entry after packing
        private List<string> names = new List<string>();

        // This contains the textures to pack
        // Used a list here so we could easily convert to array during packing
        private List<Texture2D> textures = new List<Texture2D>();

        // Keeps track of the packed entries
        private Dictionary<string, PackedTextureEntry> entriesMap = new Dictionary<string, PackedTextureEntry>();

        private Texture2D atlas;

        public TexturePacker() {
        }

        public void Add(string key, Texture2D texture) {
            this.names.Add(key);
            this.textures.Add(texture);
        }

        public void Pack() {
            this.atlas = new Texture2D(2, 2, TextureFormat.ARGB32, false); // Will expand on packing
            Rect[] rects = this.atlas.PackTextures(this.textures.ToArray(), 0, 8192, true);

            // Populate entries
            this.entriesMap.Clear();
            Assertion.Assert(this.names.Count == this.textures.Count);
            for(int i = 0; i < this.names.Count; ++i) {
                this.entriesMap[this.names[i]] = new PackedTextureEntry(this.atlas, rects[i]);
            }

            // Clear to save memory
            // These textures may also be released
            this.textures.Clear();
        }

        public PackedTextureEntry GetEntry(string key) {
            return this.entriesMap[key];
        }

    }

Usage is self explanatory. Create an instance of the packer. Add the textures that you want to pack, each associated with a string key. Call Pack(). Use GetEntry() to get an instance of PackedTextureEntry associated with the sprite. Use PackedTextureEntry.Sprite property to have access of the sprite that is from the packed texture.

TexturePacker packer = new TexturePacker();

// Let's just say you have a library of textures associated by name
foreach(TextureEntry entry in entries) {
    packer.Add(entry.Name, entry.Texture);
}

packer.Pack();

// Get a packed entry and use its sprite
PackedTextureEntry packedEntry = packer.Get("Grass");
spriteRenderer.sprite = packedEntry.Sprite;

And that’s it! It’s really simple but this thing helped in batching by a lot.

YuugeBatch
Yuuuge batch! This is from the frame debugger.

 

Some Utility Code

Every now and then, I’d like to share some of my small utility classes that I’ve made a long time ago but are still being used until now. The following are what I call some of my mini utilities. They can be used in your own Unity projects.

(Note that I’ve removed method description comments so that the code part looks more compact.)

Comment Component

A lot of times have come up where I have an object or prefab that contains a lot of components. Sometimes, I want to be able to note about the values I’ve entered for some component or state why the component is there. Sadly, Unity doesn’t have a feature where you can comment on components (let me know if you know one). However, it’s quite easy enough to roll your own “comment” component.

public class Comment : MonoBehaviour {

    [SerializeField]
    private string text;

    void Awake() {
        DestroyImmediate(this); // auto destroy to save memory
    }

    public string Text {
        get {
	    return text;
	}

        set {
	    this.text = value;
        }
    }

}

// This is the editor script. Place it under an Editor folder.
[CustomEditor(typeof(Comment))]
public class CommentEditor : Editor {

    private Comment targetComponent;

    void OnEnable() {
        this.targetComponent = (Comment)this.target;
    }

    public override void OnInspectorGUI() {
        if(targetComponent.Text == null) {
            // use an empty string so that it won't throw null pointer exception
            targetComponent.Text = "";
        }

        targetComponent.Text = GUILayout.TextArea(targetComponent.Text, GUILayout.Height(100), GUILayout.MinWidth(200));
    }

}

To use, just add the Comment component and type your comment text in the textbox.

CommentComponent

UI Image Sprite Animation

I tried to use the animation timeline for animating sprites in a UI Image. But it didn’t work or maybe I was using it wrong. I got impatient, so I turned to code.

public class ImageAnimation : MonoBehaviour {

    [SerializeField]
    private Image image;

    [SerializeField]
    private float framesPerSecond = 15;

    [SerializeField]
    private Sprite[] sprites; // The sequence of sprites comprising the animation

    private float polledTime;

    private int currentFrameIndex;

    private void Awake() {
        Assertion.AssertNotNull(this.image);
        Assertion.Assert(this.framesPerSecond > 0);

        this.polledTime = 0;

        // Reset
        this.currentFrameIndex = 0;
        SetSprite(this.currentFrameIndex);
    }

    private void Update() {
        this.polledTime += UnityEngine.Time.deltaTime;

        // We didn't cache this so we can see the effect of framesPerSecond on the fly like tweaking it in editor
        float timePerFrame = 1.0f / this.framesPerSecond;

        while(this.polledTime > timePerFrame) {
            this.polledTime -= timePerFrame;

            // Show next frame
            this.currentFrameIndex = (this.currentFrameIndex + 1) % this.sprites.Length;
            SetSprite(this.currentFrameIndex);
        }
    }

    private void SetSprite(int index) {
        this.image.sprite = this.sprites[index];
    }

}

This is very straightforward to use. Just specify an Image target, a frame rate, and the sequence of sprites to show. That’s it. It will play on loop. Nothing fancy. I’ve use this on the game over screen of Academia.

GameOver

SelectionSequence

Political Animals had a common UI where you select an item from a finite set of items using next and previous buttons. I’ve noticed that I’m repeating the same code spread across different UI screens. So I made a generic class for this.

public class SelectionSequence<T> {

    private readonly List<T> items = new List<T>();

    private int currentIndex = 0;

    public SelectionSequence(T[] array) {
        this.items.AddRange(array);
        Reset();
    }

    public void Reset() {
        this.currentIndex = 0;
    }

    public void MoveToNext() {
        this.currentIndex = (currentIndex + 1) % this.items.Count;
    }

    public void MoveToPrevious() {
        int decremented = this.currentIndex - 1;
        this.currentIndex = decremented < 0 ? this.items.Count - 1 : decremented;
    }

    public T Current {
        get {
            return this.items[this.currentIndex];
        }
    }

    public void Select(int index) {
        this.currentIndex = index;
    }

    public void Select(T item) {
        for(int i = 0; i < this.items.Count; ++i) {
            if(this.items[i].Equals(item)) {
                Select(i);
                return;
            }
        }

        throw new Exception("Can't find the item to select: " + item.ToString());
    }

    public int Count {
        get {
            return this.items.Count;
        }
    }

    public T GetAt(int index) {
        return this.items[index];
    }

}

// Usage
// Say you have an array of LanguageOption
LanguageOption[] languages = ...;
SelectionSequence<LanguageOption> langSequence = new SelectionSequence<LanguageOption>(languages);

// When next button is clicked
langSequence.MoveToNext();

// When previous button is clicked
langSequence.MoveToPrevious();

// Do something with current selection
ChangeLanguage(langSequence.Current);

This kind of selection have come up in Academia, too.

SelectionExample

These are just some of my cute little classes. They’re small but they have been very useful. Here’s some programming tip, think of making classes like making a new invention or a device. That way, you will think in terms of narrowing functionality as much as possible and expose only appropriate public methods. This will also make your classes more modular. Over time, you will develop a library of robust and reusable code.