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.
Advertisements

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.

Nightmare on Release Day

This last week has been very exhausting. It was the week of the release of Academia‘s Early Access. I thought we’d have a smooth release this time because we already have a good candidate build by September 5, Tuesday. We were releasing on September 8, Friday. Things were pretty chill. We distributed some keys to Youtubers so they can start recording their games. Then Wednesday night, one of the Youtubers reported this:

Zombies

Every single agent in the game acted like zombies with nothing to chase. They don’t do anything else. They’re stuck in this trance state for eternity. Worst of all, I can’t replicate it on my machine. Our artist, Ryan Sumo, can replicate it on his end consistently. This is an unacceptable bug because it stops the flow of the game. The bugs that are hardest to fix are those you can’t replicate, and we only found out of this ugly one two days before release.

The whole day of Thursday was spent on blindly fixing this bug. Anything I try is a just a “guess”. I build the game, upload it to our Steam testing branch, then Ryan downloads it and… “I’m sorry your fix didn’t work”. My emotions go from hopeful to heartbreak, then back to hopeful if I thought of a good guess, and back to sorrow again if the guess failed. It was very tiring.

My best guess revolved around our A* processing thread. We have a separate thread that has a queue of A* requests. The agents can enqueue an A* request whenever they need one and wait for the result. The thread checks the queue request and executes the A* search. This thread runs indefinitely. The agents in the gif are doing their default behavior while waiting for the A* result that they requested. They roam around in their current tile. My guess is that the thread stopped working such that they no longer get their results, thus their behavior of waiting in vain.

This was the unfixed code (Not the actual code. This is a shortened one.):

    // Runs the thread that constantly checks the queue
    class AStarThreadQueue {
        private ActionThread thread;
        private Queue<AStarResolution> queue = new Queue<AStarResolution>();

        public void RunThread() {
            this.thread = UnityThreadHelper.CreateThread((Action)Process);
        }

        public void Enqueue(AStarResolution resolution) {
            Assertion.AssertNotNull(resolution);
            this.queue.Enqueue(resolution);
        }

        private static readonly object SYNC_LOCK = new object();

        // This is the method that the thread executes indefinitely
        private void Process() {
            while(true) {
                if (this.queue.Count > 0) {
                    AStarResolution resolution = null;

                    lock (SYNC_LOCK) {
                        resolution = this.queue.Dequeue();
                    }

                    resolution.Execute();
                }
            }
        }
    }

This code works without problems while in Unity editor, even with hundreds of agents. But when built to an exe and tested on other computers, the thread breaks. If you know multithreading, you can probably see the problem from a mile. First, I didn’t have exception handling inside that while loop. If an exception occurs inside, the loop breaks and the thread ends. Second, the queue is not locked in Enqeue(). Based from the logs, the code

                    lock (SYNC_LOCK) {
                        resolution = this.queue.Dequeue();
                    }

returns null even when the queue count is checked and the items in it are guaranteed to be not null. This is probably due to access conflict to the queue.

This is what the fixed code looks like:

    // Runs the thread that constantly checks the queue
    class AStarThreadQueue {
        private ActionThread thread;
        private Queue<AStarResolution> queue = new Queue<AStarResolution>();

        public void RunThread() {
            this.thread = UnityThreadHelper.CreateThread((Action)Process);
        }

        public void Enqueue(AStarResolution resolution) {
            Assertion.AssertNotNull(resolution);

            lock (SYNC_LOCK) {
                this.queue.Enqueue(resolution);
            }
        }

        private static readonly object SYNC_LOCK = new object();

        // This is the method that the thread executes indefinitely
        private void Process() {
            while(true) {
                try {
                    if (this.queue.Count > 0) {
                        AStarResolution resolution = null;

                        lock (SYNC_LOCK) {
                            resolution = this.queue.Dequeue();
                        }

                        resolution.Execute();
                    }
                } catch(Exception e) {
                    // We log the error but do not end the thread
                    Debug.LogError(e.Message);
                }
            }
        }
    }

With this, Ryan finally claimed “OK, the fix seems to work!”. I cried inside. The fixed code looks somewhat easy now, but the journey to this fix was not. I tried a lot of other fixes before this. I even turned off that Graphics Jobs feature of Unity because it might have messed with our thread. It’s a stupid theory but I’m desperate. Might as well try it.

While multithreading is useful, I realized that it could also be ruthless if you don’t know what you are doing. Treat this as a cautionary tale if you use threads in your projects. Test your build on a variety of machines and with the most complex state of the game. Avoid this kind of nightmare on your release day.

Our game Academia: School Simulator is now available on Steam Early Access. It’s currently discounted at 20%. We’re still a long way to go and we have lots of features to implement. Buy it now while it’s cheap.

Things I Wish I had Done in Academia

This post is going to be a bit different. To be honest, I have ran out of programming topics to discuss that is at least as interesting as the previous one. So instead, I’ve thought about the architectural mistakes that I’ve made and wished that I implemented them differently. It might help those who want to develop games in the same genre. Consider this like sort of a post mortem but in the perspective of the programmer.

I wish I had used Behavior Trees under our GOAP framework

We are using GOAP to drive all our NPC behavior. I’ve written about it here and here. Each action inside our GOAP framework is not just a single action. Instead, we are using a sequence of multiple “atom actions” that the agent executes one after another. This way, we can easily write individual atom action classes and reuse them. A GOAP action then is just a container of atom actions.

multipleactions
A screenshot of our GOAP editor

The problem here is the sequential execution. There’s no way to simulate branching behaviors like for example, if the main sequence fails, then do this other one. If I wanted something like this, it’s either I add more preconditions to the action or create another GOAP action for the branching behavior. It’s just awkward most of the time and adds complexity. This would have been elegantly solved had I used a behavior tree instead of a sequence of actions. This will add development time for the editor but it would have been worth it. Now, I’m stuck with this current implementation because we’re just too deep into its usage.

I wish I maintained all our assets in a single large texture

This is probably my biggest mistake in this game. Like I knew this at the back of my head but didn’t do it because I was lazy and I wanted a working prototype right away. Now it’s biting me at the neck. I mentioned this in my previous post. I didn’t have to do that packing had I done this. It would have save us some game loading time and memory.

I wish I had used a text format like XML for the objects definitions

An object definition contains all the information about an object in the game. For example, say a refrigerator. Its definition will contain information like it occupies 2×1 tiles, it uses this sprites, it has this price, it should be added in this layer, it has this offset, it has to use this prefab, everything! Stupid as it may seem, but yes, we’re not using a text format for this. We are using Unity’s serialized class instead, and it has a fancy editor:

ObjectDefinitionSample

Unity’s serialized classes are very easy to write. You write the serialized class and the inspector automagically creates editor fields for them. You don’t have to write a parser! Since laziness wins, I stuck with it. The problem is that our designer or artist couldn’t use it due to edit conflicts. I’m almost always updating this data and my edits are much more critical so I always end up overriding theirs.

What happened is that I ended up making another definition file which our designer maintains to avoid conflict. Now we have multiple definition files and this is bad! It’s also expected that this will bite me soon because this does not sit well for modding support.

Life would have been different if the definitions were maintained in a single XML file. Conflicts are easier to fix and my team mates would have been happier. Sure, I could generate an XML file from my existing definition. But my point is that’s effort that could have been avoided.

I wish I included the body in animation clips

Our NPCs play some animations like when they are eating, reading a book, cooking, etc. I made this by using a prefab that contains the hands and the animations. Whenever an NPC is generated, I also add the hands prefab to them. I separated the character prefab and hands prefab so it’s easier to maintain the different classes like students, teachers, workers, etc.

HandsPrefab
The “Hands” prefab and all its glory

Unfortunately, the hands prefab really only has the hands. It doesn’t include the character’s body. The animation clips then can only animate hands. This is a problem because later on, we may want to animate the body like when the character is giggling, jumping, shaking, or angry. The current implementation may be more maintainable but this drastically reduces the animation possibilities.

Conclusion

This is obviously an incomplete list but these are probably the major ones. The thing is, I can’t make a major refactor right now. We are at the brink of release. Academia will be out on Early Access on September 8! Even with these mishaps, the state of the current game is working great. I’ll most likely fix some of the stuff here in the near future.

Hope you have enjoyed this and I’ll see you on the next one.

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.

 

Simple FSM Framework Part 2: More on Actions

The FSM framework described in part 1 requires the user to make action classes. These action classes can then be reused in any state. This makes the framework very extensive and flexible. This is actually my favorite feature in Playmaker. Playmaker comes with a wide collection of premade action classes. At the same time, you can also add your own actions by extending a base class and the FSM editor can pick up these new actions. A framework of my own has to have the same system.

The following is one of my generic actions:

	public class MoveAction : FsmAction {

		private Transform transform;
		private Vector3 positionFrom;
		private Vector3 positionTo;
		private float duration;
		private string timeReference;
		private string finishEvent;
		private Space space;

		private CountdownTimer timer;

		public MoveAction(FsmState owner) : base(owner) {
			this.timer = new CountdownTimer(1); // uses default time reference
		}

		public MoveAction(FsmState owner, string timeReferenceName) : base(owner) {
			this.timer = new CountdownTimer(1, timeReferenceName);
		}

		public void Init(Transform transform, Vector3 positionFrom, Vector3 positionTo, float duration, string finishEvent, Space space = Space.World) {
			this.transform = transform;
			this.positionFrom = positionFrom;
			this.positionTo = positionTo;
			this.duration = duration;
			this.finishEvent = finishEvent;
			this.space = space;
		}

		public override void OnEnter() {
			if(Comparison.TolerantEquals(duration, 0)) {
				Finish();
				return;
			}

			if(VectorUtils.Equals(this.positionFrom, this.positionTo)) {
				// positionFrom and positionTo are already the same
				Finish();
				return;
			}

			SetPosition(this.positionFrom);
			timer.Reset(this.duration);
		}

		public override void OnUpdate() {
			timer.Update();

			if(timer.HasElapsed()) {
				Finish();
				return;
			}

			// interpolate position
			SetPosition(Vector3.Lerp(this.positionFrom, this.positionTo, timer.GetRatio()));
		}

		private void Finish() {
			// snap to destination
			SetPosition(this.positionTo);

			if(!string.IsNullOrEmpty(finishEvent)) {
				GetOwner().SendEvent(finishEvent);
			}
		}

		private void SetPosition(Vector3 position) {
			switch(this.space) {
			case Space.World:
				this.transform.position = position;
				break;

			case Space.Self:
				this.transform.localPosition = position;
				break;
			}
		}

	}

It’s basically an action that moves an object from point A to B at some duration. It also accepts a “Finished” event such that when the action is done, it sends/triggers this event towards the owning FSM which may cause a state change.

This is how it can be used:

        private void PrepareFsm() {
            // States
            FsmState goHome = fsm.AddState("GoHome");
            ...

            // GoHome actions
            {
                MoveAction move = new MoveAction(goHome);
                float duration = homeDistance / this.moveSpeed; // Calculate duration by speed
                move.Init(this.transform, this.transform.position, homePosition, duration, FINISHED);

                goHome.AddAction(move);
            }

            ...
        }

There are a lot of generic actions with this flavor. I have actions like RotateToTarget, ScaleByDuration, SetColorByDuration, TimedWait, etc. The good thing is I only have to write these actions once and they can be reused in any game.

Generic Delegate Action

So far I’ve shown that writing reusable action classes are good. They can also be bad. One of my gripes in Playmaker is making action classes that only uses single calls to other components. In my framework, I used to write action classes like this:

    public class Fire : FsmAction {

        private Ship ship;
        private string finishEvent;

        public Fire(FsmState owner, Ship ship, string finishEvent) : base(owner) {
            this.ship;
            this.finishEvent = finishEvent;
        }

        public override void OnEnter() {
            ship.Fire();
            GetOwner().SendEvent(this.finishEvent);
        }

    }

The only significant call here is ship.Fire(). But since I have to interface with the framework, I have to make a new class for it. Not only is this verbose, it kills productivity. This single line calls in an FSM happens a lot.

To fix this, I made a generic action that accepts delegates for its OnEnter(), OnUpdate(), and OnExit() routines. This way, I could call one liners such as ship.Fire() through an anonymous method thus avoiding making a new class altogether.

	public class FsmDelegateAction : FsmAction {

		public delegate void FsmActionRoutine(FsmState owner);

		private FsmActionRoutine onEnterRoutine;
		private FsmActionRoutine onUpdateRoutine;
		private FsmActionRoutine onExitRoutine;

		public FsmDelegateAction(FsmState owner, FsmActionRoutine onEnterRoutine) : this(owner, onEnterRoutine, null, null) {
		}

		public FsmDelegateAction(FsmState owner, FsmActionRoutine onEnterRoutine, FsmActionRoutine onUpdateRoutine, FsmActionRoutine onExitRoutine = null) : base(owner) {
			this.onEnterRoutine = onEnterRoutine;
			this.onUpdateRoutine = onUpdateRoutine;
			this.onExitRoutine = onExitRoutine;
		}

		public override void OnEnter() {
			if(onEnterRoutine != null) {
				onEnterRoutine(GetOwner());
			}
		}

		public override void OnUpdate() {
			if(onUpdateRoutine != null) {
				onUpdateRoutine(GetOwner());
			}
		}

		public override void OnExit() {
			if(onExitRoutine != null) {
				onExitRoutine(GetOwner());
			}
		}

	}

Now instead of making a new Fire action class, I could just use this action instead:

        // Say the Fsm instance is inside the Ship component
        private void PrepareFsm() {
            // States
            ...
            FsmState fire = fsm.AddState("Fire");
            ...

            // Fire actions
            {
                fire.AddAction(new FsmDelegateAction(fire, delegate(FsmState owner) {
                    Fire();
                    owner.SendEvent(FINISHED);
                }));
            }

            ...
        }

This is less verbose. I’m still interfacing with the framework but with less code. Most FSM actions don’t need to be a class of their own. If they need to be, then sure we could refactor that in another action class.

This is how a code based FSM becomes more interesting than an editor based one. You can do manipulations in code that you cannot do in an editor. You can manage the FSM better. You gain a lot of options to organize FSMs through code.

Simple FSM Framework Part 1: The Making

I remember a project which I lead that heavily used Playmaker for its systems. This was the time when Playmaker was still in its first couple of months and I got pretty excited when I tried it. For those of you who are not familiar, Playmaker is a Unity asset that helps you create FSM graphs and add functionality without code. It got so popular that it has become the leading “visual scripting” asset of Unity.

Short version of the story: that project became a disgusting pile of mess. The messiness of FSM wiring is way worse than spaghetti code. At least code could be refactored. It was so bad that I vow not to primarily use visual scripting to run the complex systems of a game ever again.

A part of Defender unit FSM. Looks like spaghetti, yum!
This is not part of that project but you get the idea.

However, I didn’t hate Playmaker. It showed a good data model on how a finite state machine works that can be applied to games. So I made my own bare bones FSM framework based from it so that I can still make FSM graphs through code. Used wisely, FSMs can be a great way to organize simple behavior. I’ve been using this framework ever since. I’m still using Playmaker but only as a visual reference. All of my FSMs are now in code.

I’m going to show you how I did it in this post. There will be no github repository for this because honestly, I’m too lazy to extract it from my library. My intent is to have you read code so you can make your own FSM framework and hopefully improve it on your own.

High Level Design

My design is based on Playmaker’s model. These are the main concepts:

  • FsmAction – Represents an action that is executed/executing on a single state
  • Events – It is that thing that causes state change. This can be easily represented as strings.
  • FsmState – Represents a state in the FSM. It has a collection of actions and transitions.
  • Transitions – Represents the link to another state. This can be easily represented as a pair of event (string) and FsmState.
  • Fsm – Contains a certain set of FsmState instances that comprises a single FSM graph. Provides methods to send events and thus changes the current state.

FsmAction Code

An FsmAction is just a base class for concrete actions to implement. The way the framework is used is that there will be a collection of predefined action classes that can be used such as Move, Rotate, TimedWait, etc. At the same time, custom actions could also be implemented. Obvious examples are actions that are specific to a game.

public abstract class FsmAction {

    private readonly FsmState owner;

    public FsmAction(FsmState owner) {
        this.owner = owner;
    }

    public FsmState GetOwner() {
        return owner;
    }

    public virtual void OnEnter() {
        // may or may not be implemented by deriving class
    }

    public virtual void OnUpdate() {
        // may or may not be implemented by deriving class
    }

    public virtual void OnExit() {
        // may or may not be implemented by deriving class
    }

}

This is pretty straightforward. The most important here are the three methods. OnEnter() is invoked when a state has been entered. OnUpdate() is called repeatedly every frame while on a certain state. OnExit() is invoked when the current state will be changed to a new one. The member FsmState is needed so that actions can send events to it (change the current state).

Why is it not an interface? The intent is that actions should be small modular classes deriving from FsmAction. An existing big class, say some kind of big manager, can’t just implement an interface and use that big class as an FsmAction. This also prevents usage of MonoBehaviour classes as FsmAction instances.

FsmState Code

FsmState is just a collection of actions and transitions to other states. It provides the methods appropriate to setup states.

public class FsmState {

    private readonly string name;
    private readonly Fsm owner;

    // Transitions are just pairs of event and FsmState
    // Events are just strings
    private readonly Dictionary<string, FsmState> transitionMap = new Dictionary<string, FsmState>();

    private readonly List<FsmAction> actionList = new List<FsmAction>();

    public FsmState(string name, Fsm owner) {
        this.name = name;
        this.owner = owner;
    }

    public string Name {
        get {
            return name;
        }
    }

    public void AddTransition(string eventId, FsmState destinationState) {
        // can't have two transitions for the same event
        Assertion.Assert(!transitionMap.ContainsKey(eventId), string.Format("The state {0} already contains a transition for event {1}.", this.name, eventId));
        transitionMap[eventId] = destinationState;
    }

    public FsmState GetTransition(string eventId) {
        // May return null if there's no such transition
        return transitionMap.Find(eventId);
    }

    public void AddAction(FsmAction action) {
        Assertion.Assert(!actionList.Contains(action), "The state already contains the specified action.");
        Assertion.Assert(action.GetOwner() == this, "The owner of the action should be this state.");
        actionList.Add(action);
    }

    public IEnumerable<FsmAction> GetActions() {
        return actionList;
    }

    public void SendEvent(string eventId) {
        // Just delegate to the owner Fsm
        this.owner.SendEvent(eventId);
    }

}

Fsm Code

Fsm is like the central hub of the framework. You make an instance of this class then it provides methods to create FsmState instances. Those FsmState instances can then be setup to your liking (actions and transitions).

public class Fsm {

    private readonly string name;

    private FsmState currentState;

    // Collection of all states using the state name as key
    private readonly Dictionary<string, FsmState> stateMap = new Dictionary<string, FsmState>();

    public Fsm(string name) {
        this.name = name;
        currentState = null;
    }

    public string Name {
        get {
            return name;
        }
    }

    public FsmState AddState(string name) {
        // state names should be unique
        Assertion.Assert(!stateMap.ContainsKey(name), "The FSM already contains a state with the specified name: " + name);

        FsmState newState = new FsmState(name, this);
        stateMap[name] = newState;
        return newState;
    }

    private delegate void StateActionProcessor(FsmAction action);

    private void ProcessStateActions(FsmState state, StateActionProcessor actionProcessor) {
        FsmState stateOnInvoke = this.currentState;

        IEnumerable<FsmAction> actions = state.GetActions();
        foreach(FsmAction action in actions) {
            actionProcessor(action);

            if(this.currentState != stateOnInvoke) {
                // this means that the action processing caused a state change
                // we don't continue with the rest of the actions
                break;
            }
        }
    }

    public void Start(string stateName) {
        FsmState state = stateMap.Find(stateName);
        Assertion.AssertNotNull(state);
        ChangeToState(state);
    }

    private void ChangeToState(FsmState state) {
        if(this.currentState != null) {
            // if there's an active current state, we exit that first
            ExitState(this.currentState);
        }

        this.currentState = state;
        EnterState(this.currentState);
    }

    private void EnterState(FsmState state) {
        ProcessStateActions(state, delegate(FsmAction action) {
            action.OnEnter();
        });
    }

    private void ExitState(FsmState state) {
        FsmState currentStateOnInvoke = this.currentState;

        ProcessStateActions(state, delegate(FsmAction action) {
            action.OnExit();
            if(this.currentState != currentStateOnInvoke) {
                // this means that the action's OnExit() causes the FSM to change state
                // note that states should not change state on exit
	        throw new Exception("State cannot be changed on exit of the specified state.");
            }
        });
    }

    public void Update() {
        if(this.currentState == null) {
            return;
        }

        ProcessStateActions(this.currentState, delegate(FsmAction action) {
            action.OnUpdate();
        });
    }

    public FsmState GetCurrentState() {
        return this.currentState;
    }

    public void SendEvent(string eventId) {
        if(currentState == null) {
            Debug.LogWarning(string.Format("Fsm {0} does not have a current state. Check if it was started.", this.name));
            return;
        }

        FsmState transitionState = this.currentState.GetTransition(eventId);
        if(transitionState == null) {
            #if UNITY_EDITOR
            // log only in Unity Editor since it lags the game even if done in build
            Debug.LogWarning(string.Format("The current state {0} has no transtion for event {1}.", this.currentState.GetName(), eventId));
            #endif
        } else {
            ChangeToState(transitionState);
        }
    }

}

The only thing special here is ProcessStateActions(). It is the common algorithm for traversing state actions. I made it this way so I don’t have to repeat this pattern whenever I traverse state actions. As you can see here, it is invoked in EnterState(), ExitState(), and Update().

This is pretty much it. The FSM framework is done.

How to use?

Let’s just say we’re making a runner game and we are developing the main runner character. Let’s say the following would be its FSM behavior graph:

RunnerFsm

This is self explanatory. That starting state would be the character running. When Jump event triggers, like the player presses the jump button, it goes to jumping state. From jumping, if it hits the ground, it goes back to running state. If it hits an obstacle, then it dies.

Their are many ways to use the framework. The most common one is to use it in a MonoBehaviour. This is how it is then set up:

public class RunnerCharacter : MonoBehaviour {

    [SerializeField]
    private float moveSpeed;

    private Fsm fsm = new Fsm("RunnerCharacter");

    private void Awake() {
        PrepareFsm();
    }

    // Only keeping constant of the starting state since it will be needed for starting the FSM
    private const string RUNNING = "Running";

    // Events
    private const string JUMP = "Jump";
    private const string HIT_GROUND = "HitGround";
    private const string HIT_OBSTACLE = "HitObstacle";

    private void PrepareFsm() {
        // States
        FsmState running = fsm.AddState(RUNNING);
        FsmState jumping = fsm.AddState("Jumping");
        FsmState die = fsm.AddState("Die");

        // Actions

        // Running
        {
            MoveConstantly move = new MoveConstantly(running);
            move.Init(this.transform, this.moveSpeed);
            running.AddAction(move);

            TriggerAnimator animationTrigger = new TriggerAnimator(running, "Run");
            running.AddAction(animationTrigger);
        }

        // Jumping
        {
            JumpAction jump = new JumpAction(jumping);
            jumping.AddAction(jump);

            TriggerAnimator animationTrigger = new TriggerAnimator(running, "Jump");
            running.AddAction(animationTrigger);
        }

        // Die
        {
            TriggerAnimator animationTrigger = new TriggerAnimator(running, "Die");
            running.AddAction(animationTrigger);
        }

        // Transitions
        running.AddTransition(JUMP, jumping);
        running.AddTransition(HIT_OBSTACLE, die);

        jumping.AddTransition(HIT_GROUND, running);

        // Auto start the FSM (sometimes it may be started else where)
        // Start() can be invoked anywhere like respawning a character
        this.fsm.Start(RUNNING);
    }

    private void Update() {
        // Process input
        if(Input.GetKeyDown(KeyCode.Space)) {
            this.fsm.SendEvent(JUMP);
        }

        // Don't forget to update
        this.fsm.Update();
    }

    private void OnCollisionEnter(Collision collision) {
        if(...) {
            // Collided with ground
            this.fsm.SendEvent(HIT_GROUND);
        }

        if(...) {
            // Collided with obstacle
            this.fsm.SendEvent(HIT_OBSTACLE);
        }
    }

}

I usually make a method for preparing the FSM. I usually name it PrepareFsm() and invoked on Awake(). In PrepareFsm(), I perform 3 preparations which are the states, actions, and transitions. I make the states first because those instances are needed when adding transitions. The classes MoveConstantly, JumpAction, and TriggerAnimator are defined FsmAction classes.

Events are natural candidates to become constants. They can be made as public if you want to expose the sending of events from other parts of the program. However, I don’t recommend that.

Every time you want to change the state, you just have to call Fsm.SendEvent() as can be seen here in Update() and OnCollisionEnter().

A common use case is to determine what the current state is. This can be done by caching the added state in a member variable instead of a local one. The cached state can then be compared with the state returned with Fsm.GetCurrentState().

private FsmState running;

private void PrepareFsm() {
    // States
    this.running = fsm.AddState(RUNNING); // Cache in member variable
    FsmState jumping = fsm.AddState("Jumping");
    FsmState die = fsm.AddState("Die");

    ...
}

private void Update() {
    // Process input
    if (Input.GetKeyDown(KeyCode.Space)) {
        if (this.fsm.GetCurrentState() == this.running) {
            // Jump only when on running state
            this.fsm.SendEvent(JUMP);
        }
    }

    this.fsm.Update();
}

This looks more tedious than Playmaker.

It is but it’s more useful for me. The reason I made the framework is so that I don’t have to use Playmaker if I ever do need FSMs. It forces me to ground my work using code. I’m afraid that if I start using Playmaker, it will creep out of control and will eventually become unmanageable. With FSMs done in code, I can apply a lot of tricks to make them manageable. Or if the FSM itself is messy, I could opt to refactor the whole thing without dealing with a Playmaker graph.

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.

Reflection Series – Part 3: Attributes are Magic

Attributes in C# are those things wrapped in “[]” that are sprinkled on classes, properties, or variables. In Unity, I usually use [SerializeField] so that a variable becomes editable in the editor but still remains private or protected in code if I wanted to. There are other attributes, too, like Range, ExecuteInEditMode, HideInInspector, DisallowMultipleComponent, etc. Somewhere in Unity’s processes access these attributes through reflection and executes code that the attribute dictates. The coolest part is you can make your own attributes. The following is a very simple attribute:

[AttributeUsage(AttributeTargets.Property)]
public class PropertyGroup : Attribute {

    private readonly string name;

    public PropertyGroup(string name) {
        this.name = name;
    }

    public string Name {
        get {
            return name;
        }
    }

}

It’s an attribute that can be attached to properties (AttributeTargets.Property). It requires a string name. This is how it can be used:

        ...

        [PropertyGroup("Settings")]
        public string Gender {
            get {
                return gender;
            }

            set {
                this.gender = value;
            }
        }

        [PropertyGroup("Settings")]
        public string Type {
            get {
                return type;
            }

            set {
                this.type = value;
            }
        }

        [PropertyGroup("OrientationIds")]
        public string DownSpriteId {
            get {
                return downSpriteId;
            }

            set {
                this.downSpriteId = value;
            }
        }

        [PropertyGroup("OrientationIds")]
        public string RightSpriteId {
            get {
                return rightSpriteId;
            }

            set {
                this.rightSpriteId = value;
            }
        }

        ...

We use PropertyGroup attribute as a grouping mechanism for our generic editor. What we do is in our editor code, we look for this attribute and collect such properties in their own container before rendering them. There are many ways to access an attribute through reflection. The following is one way:

public static T GetCustomAttribute<T>(PropertyInfo property) where T : Attribute {
    Attribute attribute = Attribute.GetCustomAttribute(property, typeof(T));
    return attribute as T;
}

// Usage
PropertyGroup group = GetCustomAttribute<PropertyGroup>(propertyInfo);

// Do something with the attribute like access its name
List<PropertyInfo> propertyList = GetPropertyList(group.Name);

With this, we can change the look of our editor by just adding attributes to our classes.

GroupedProperties

Other Uses

Persistence

In Part 2 of this series, I discussed an XML writer/reader by reading properties of classes. Aside from this, we also have a property attribute named Persist to selectively write/read properties with such attribute. The attribute also allows specification of a default value. We heavily use this attribute in our persistence system. This is useful for properties that are not present in old save files and you want a default value for them.

    [AttributeUsage(AttributeTargets.Property)]
    public class Persist : Attribute {

        private object defaultValue;

        public Persist() {
        }

        public Persist(object defaultValue) {
            this.defaultValue = defaultValue;
        }

        public object DefaultValue {
            get {
                return defaultValue;
            }
        }

    }

    // Sample usage
    [Persist]
    public float PolledTime {
        get {
            return polledTime;
        }

        set {
            this.polledTime = value;
        }
    }

    [Persist(1)]
    public int Day {
        get {
            return day;
        }

        set {
            this.day = value;
        }
    }

    [Persist(1)]
    public int Year {
        get {
            return year;
        }

        set {
            this.year = value;
        }
    }

    ...

Class Browser

In Part 1, I wrote about loading classes using their class names. As such, we have a lot of different editors where a user can select from a selection of different classes that derive from a single base class. The amount of classes written for these editors can get out of hand so we made a class level property to group classes into their respective domains.

    [AttributeUsage(AttributeTargets.Class)]
    public class Group : Attribute {

        private readonly string name;

        public Group(string name) {
            this.name = name;
        }

        public string Name {
            get {
                return name;
            }
        }

    }

    // Usage
    [Group("Game.CharacterNeeds")]
    public class AddNeedAmount : ComponentAction<CharacterNeeds> {
        ...
    }

    [Group("Game.Task")]
    class GetCurrentTaskEffortPerTile : ComponentAction<TaskDoer> {
    }

With this attribute, we can make our class browsers to look like this:

ClassBrowser

Conclusion

Reflection is a worthy tool to add to your gamedev toolbox. It’s powerful and useful. What I did in this series is probably just the tip of an iceberg. I’ve read about modders who opened up, ripped, and replaced game parts of C# games using reflection. Yikes!

I’m going to end the series for now. I may add to it later. I hope I have convinced you that reflection is a cool toy to learn.

Reflection Series – Part 2: Harnessing Properties

One of my favorite features in reflection is the ability to know about the properties of a certain instance at runtime. This has helped a lot in making tools to aid game development.

Basics

The following code is the simplest way to iterate through the properties of an instance:

// Let's say there's some instance named myInstance
Type type = typeof(myInstance);

// Get the properties that are public and not static
PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);

foreach(PropertyInfo property in properties) {
    // Do something with property...
}

PropertyInfo contains the information about a property. You can get its getter and setter methods. You can invoke them. You can get its return type. You can query the attributes attached to the property. You will know a lot (just head over to its API reference).

Example Usage

One utility class that I’ve made is a generic XML writer and loader that can accept any instance and write the instance’s public properties to an XML. This way, I don’t have to make a custom XML writer code for each type of data. I can just use this class and tell it to write the instance.

I don’t write all public properties. I only select those with public getter and setter. The following is a utility method if such property is meant to be written:

public static bool IsVariableProperty(PropertyInfo property) {
    // should be writable and readable
    if(!(property.CanRead && property.CanWrite)) {
        return false;
    }

    // methods should be public
    MethodInfo getMethod = property.GetGetMethod(false);
    if(getMethod == null) {
        return false;
    }

    MethodInfo setMethod = property.GetSetMethod(false);
    if(setMethod == null) {
        return false;
    }

    return true;
}

This is how I built the writer class (showing only the important parts):

class InstanceWriter {

    private readonly Type type;
    private PropertyInfo[] properties;

    // A common delegate for writing a property of each type
    private delegate void PropertyWriter(XmlWriter writer, PropertyInfo property, object instance);
    private Dictionary<Type, PropertyWriter> attributeWriterMap = new Dictionary<Type, PropertyWriter>();

    // Constructor
    public InstanceWriter(Type type) {
        this.type = type;
        this.properties = this.type.GetProperties(BindingFlags.Public | BindingFlags.Instance); // Cached

        // Populate map of writers
        this.attributeWriterMap[typeof(string)] = WriteAsAttribute;
        this.attributeWriterMap[typeof(int)] = WriteAsAttribute;
        this.attributeWriterMap[typeof(float)] = WriteAsAttribute;
        this.attributeWriterMap[typeof(bool)] = WriteAsAttribute;
        // ... More types can be added here if needed
    }

    // Writes the specified instance to the writer
    public void Write(XmlWriter writer, object instance) {
        writer.WriteStartElement(this.type.Name);

        // Traverse properties
        foreach (PropertyInfo property in this.properties) {
            if (!TypeUtils.IsVariableProperty(property)) {
                // Not a candidate to be written
                continue;
            }

            // Must have a writer
            PropertyWriter propWriter = null;
            if (this.attributeWriterMap.TryGetValue(property.PropertyType, out propWriter)) {
                // Invokes the property writer
                propWriter(writer, property, instance);
            }
        }

        writer.WriteEndElement();
    }

    // Writer methods. There are more of these to support the types you need to support.
    private static void WriteAsAttribute(XmlWriter writer, PropertyInfo property, object instance) {
        // Invoking the getter using reflection
        object value = property.GetGetMethod().Invoke(instance, null);
        if (value != null) {
            writer.WriteAttributeString(property.Name, value.ToString());
        }
    }

}

This class just maintains a dictionary of writer methods mapped by Type. During traversal of properties, it checks if a property needs to be written and that it has a mapped writer method. PropertyInfo.PropertyType was used to get the type of the property. It then proceeds to invoke that writer method which writes the value to the XmlWriter.

The actual class is more elaborate than this. There’s a separate map for property writers that needs child elements. For example, Vector3 needs a child element and its xyz values are stored as attributes. We also took it further by checking if the property implements a custom interface of ours named IXmlSerializable and invokes the writer method of that property.

This is then how it is used:

InstanceWriter writer = new InstanceWriter(typeof(MyClass));
writer.Write(xmlWriter, myClassInstance); // Writes a whole element representing MyClass

My XmlLoader was made using the same concept only that the mapped methods now invoke the setter of the property. This is one of the loader methods:

private static void LoadString(SimpleXmlNode node, PropertyInfo property, object instance) {
    if(!node.HasAttribute(property.Name)) {
        // No value from XML. Set a default value.
        SetDefault(property, instance);
        return;
    }

    string value = node.GetAttribute(property.Name);
    property.GetSetMethod().Invoke(instance, new object[] { value });
}

Other Uses

I’ve made a generic data Unity editor that can support any type of data class as long as they expose the editable variables in the form of properties. As you can see in my other posts, most of our data editors have the same look. That’s because we are using the same base code for the editor and provide the custom rendering when necessary.

CharacterSpritesEditor
One of our generic data editors

In part 1 of this series where I talked about loading instances from mere string, we are also using properties manipulation to expose the variables of such instances in the editor. The following is a screenshot from our GOAP data editor.

GoapVariables

All of these are possible because of reflection.