entity Posts

Unity Ash – A different way of thinking about making games in Unity

Unity Ash – A different way of thinking about making games in Unity

Over a year ago I decided to scratch an itch and see if I could get Richard Lord’s Ash framework to work in Unity. It actually turned out to be far easier than I had imagined. A few people contacted me as they wanted to use it for production games so I decided to do a little more work on it a few months later to fix some of the easily solved issues with my quick port.

Unfortunately I lacked any spare time to work on it until now. This week I spent 3 days rewriting the framework from scratch. I improved many things, making it much more Unity-friendly, and generally easier to use. Because of the differences from the AS3 version of Ash I now describe it as “heavily inspired” rather than a port.

Unity-Ash Upgrades

Unity-Ash Upgrades

A while back I decided to scratch an itch and see if Richard Lord’s Ash Entity Framework could be ported to Unity. Well I was pleasantly surprised that it did port quite easily (with some help from David Arno’s .NET port) and worked well enough that I could also port Richard’s Asteroids game over to Unity too.

Since then I have had a few people contact me interested in using the port for their own projects so I decided to give it a little more love and polish.

Part 1 – Separation

First things first was to split the Ash library from the Asteroids example project so you dont have to include the entire Asteroids port in every single one of your games (madness). So now the Unity Ash project can be found here:

https://github.com/mikecann/Unity-Ash

..and the Asteroids project (which uses the Untity-Ash project) lives here:

https://github.com/mikecann/UnityAshteroids

Now all that you need to do to is to clone (or include as submodule) Unity-Ash into your game’s Assets folder and you should be good to go, simples!

Part 2 – GetComponents

Next up was performance. I knew that the performance of Unity-Ash was the biggest stumbling block and unfortunately it seemed like a fairly fundamental one thanks to some holes in the Unity API (more on that later). However, I knew there were a few low-hanging-performance-fruits I could pick that should speed up things a bit.

To experiment with things I setup a separate Unity project for the performance tests and included Unity-Ash from GitHub.

2014-12-10_09-30-51

The key performance bottleneck in Unity-Ash is the way the code checks for component additions and removals. Dynamic component addition and removal is key to how Ash functions and in AS3 because it was all custom code we could just fire an event when a component is added or removed from an Entity. Because Unity-Ash tries to piggyback on top of Unity’s existing Entity (GameObject) / Component architecture we dont actually have access to the GameObject source and thus cant trigger events when a component is added or removed.

The solution I came up with is to add a component to each GameObject which acts like the Entity. It is responsible for checking to see if components have been added or removed, to do this it gets a list of all the components in the GameObject each frame and compares against its internal cache to see if any have been added or removed. This solution works well, however you can probably see the performance hit involved with getting a list of components from Unity for each GameObject, each frame will likely be quite high.

Because this listing of components was so crucial to performance I decided to write some tests to see what is the fastest way of doing that:

public class GetComponentTests : MonoBehaviour
{
	public int iterations = 10000000;
	public int repeats = 3;

	public GameObject noComponents;
	public GameObject manyComponents;
	public List<Component> components;

	public void TestAll()
	{
		components = new List<Component>();
		TestHelpers.Execute(iterations, repeats, "Empty Function", TestEmpty);
		TestHelpers.Execute(iterations, repeats, "Get Components With No Components", NoComponentsGetComponents);
		TestHelpers.Execute(iterations, repeats, "Get Components With Many Components", ManyComponentsGetComponents);
		TestHelpers.Execute(iterations, repeats, "Get Components With No Components List", NoComponentsGetComponentsList);
		TestHelpers.Execute(iterations, repeats, "Get Components With Many Components List", ManyComponentsGetComponentsList);

		Debug.Log("components " + components.Count);
	}        

	public void TestEmpty()
	{
	}

	public void NoComponentsGetComponents()
	{
		noComponents.GetComponents<Component>();
	}

	public void ManyComponentsGetComponents()
	{
		manyComponents.GetComponents<Component>();
	}

	public void NoComponentsGetComponentsList()
	{
		noComponents.GetComponents<Component>(components);
	}

	public void ManyComponentsGetComponentsList()
	{
		manyComponents.GetComponents<Component>(components);
	}
}

I run each of these 10 million times then repeat 3 times and average:

1) “TestEmpty” is my control test test to get a sense of the cost of simply calling an empty function. That averaged to 0ms elapsed
2) “NoComponentsGetComponents” I test getting a list of components when the GameObject is empty (other than Transform), that averaged to 22ms.
3) “ManyComponentsGetComponents” I test getting a list of components when there are 20 components (plus Transform) to see what the cost of getting additional components would be, that averaged to 35ms.
4) “NoComponentsGetComponentsList” is the same as 2) except I avoid an internal memory allocation my passing in a List to populate the return with, that averaged to 5ms.
5) “ManyComponentsGetComponentsList” is the same as 3) except I pass in the List again, that averaged to 15ms.

So in summary, I learned its much faster if I pass in a list to GetComponents, which makes sense as I avoid the memory allocation associated with returning a new array each time. As a result I folded this performance improvement into Unity-Ash.

Part 3 – Unity vs Ash

These tests are all well and good but 10 million iterations of GetComponents in standalone is probably an unlikely use case in the standard game so in addition I wanted to test what the actual performance hit you would get if you used Unity-Ash in a game instead of the standard Unity way.

To test this I set up another scene that creates and updates 5,000 asteroids on the screen.

upout

I time how long they create then I count how many frames I get in 10 seconds of updating them. Each asteroid has a 2D rigid body and a very simple controller script that wraps the Asteroids position on the screen:

2014-12-10_10-15-54

public class AsteroidController : MonoBehaviour
{
	private Bounds bounds;

	void Awake()
	{
		var size = Camera.main.ScreenToWorldPoint(new Vector2(Screen.width, Screen.height));
		bounds = new Bounds(Vector3.zero, new Vector3(size.x * 2, size.y * 2));
	}

	void Update()
	{
		if (transform.position.x < bounds.min.x)
		{
			transform.position = new Vector3(transform.position.x + bounds.size.x, transform.position.y, transform.position.z);
		}
		if (transform.position.x > bounds.max.x)
		{
			transform.position = new Vector3(transform.position.x - bounds.size.x, transform.position.y, transform.position.z);
		}
		if (transform.position.y < bounds.min.y)
		{
			transform.position = new Vector3(transform.position.x, transform.position.y + bounds.size.y, transform.position.z);
		}
		if (transform.position.y > bounds.max.y)
		{
			transform.position = new Vector3(transform.position.x, transform.position.y - bounds.size.y, transform.position.z);
		}
	}
}

This was the base test and it took about 440ms to create 5000 asteroids and processed 83 frames over 10 seconds (8.3FPS).

Now I had my base I decided to setup the same scenario but using Unity-Ash to drive the updates. So now the Asteroid looks like this:

2014-12-10_10-19-42

Notice that there is no controller for the Asteroid, now all the update logic happens in a system:

public class MovementSystem : SystemBase
{
	private Bounds bounds;
	private NodeList nodes;

	public MovementSystem()
	{
		var size = Camera.main.ScreenToWorldPoint(new Vector2(Screen.width, Screen.height));
		bounds = new Bounds(Vector3.zero, new Vector3(size.x * 2, size.y * 2));
	}

	override public void AddToGame(IGame game)
	{
		nodes = game.GetNodeList<MovementNode>();
	}

	override public void Update(float time)
	{
		var cam = Camera.main;
		for (var node = (MovementNode)nodes.Head; node != null; node = (MovementNode)node.Next)
		{
			var transform = node.Transform;
			var rigidbody = node.Rigidbody;

			if (transform.position.x < bounds.min.x)
			{
				transform.position = new Vector3(transform.position.x + bounds.size.x, transform.position.y, transform.position.z);
			}
			if (transform.position.x > bounds.max.x)
			{
				transform.position = new Vector3(transform.position.x - bounds.size.x, transform.position.y, transform.position.z);
			}
			if (transform.position.y < bounds.min.y)
			{
				transform.position = new Vector3(transform.position.x, transform.position.y + bounds.size.y, transform.position.z);
			}
			if (transform.position.y > bounds.max.y)
			{
				transform.position = new Vector3(transform.position.x, transform.position.y - bounds.size.y, transform.position.z);
			}
		}
	}

	override public void RemoveFromGame(IGame game)
	{
		nodes = null;
	}
}

The update logic is functionally exactly the same as the AsteroidController except its now contained within a system.

This time it took 595ms to create the Asteroids and we processed 33 frames over 10 seconds (3.3FPS).

So immediately you can see there is a large performance hit in using Ash-Unity over regular Unity (8.3FPS compared to 3.3FPS). To confirm that it was the extra overhead of checking for new components on each asteroid rather than the internal updating mechanism of the Systems in Ash I decided to turn off checking for component updates..

2014-12-10_10-40-02

Sure enough the frame rate went back up (in fact higher!) than the Unity update rate of 8.3FPS to 8.6FPS.

So with this in mind I decided to add an option to the Entity component that lets you choose how often it checks for new components:

2014-12-10_10-42-02

The reasoning is that its actually quite rare that you change the components after the initial creation of the object (at least that’s what I found) and thus by reducing the number of times the Entity component checks for updates we should be able to increase the performance.

Sure enough, when set to “Every Other Frame” the framerate goes up to 4.5FPS then set to “Every 10 Frames” it goes up to 7.4 FPS. The final setting “If Component Count Changes” attempts to skip the iteration of the components by comparing the number of components against the previous frame, this results in 7.5 FPS.

So the short of the long is that you can get the same as or higher FPS using Unity-Ash so long as you know beforehand how often you are going to be added or removing components. If you have entities that is likely never to have components added or removed then set it to update “Never” and enjoy great FPS with the power of using Ash.

Just as an addendum to this, I have submitted a feature request to Unity to add in events to GameObject that we can listen to that are fired when components are added or removed, this would obviously remove 99.9% of these performance issues from Unity Ash so I would love your votes:

http://feedback.unity3d.com/suggestions/componentadded-slash-removed-events-on-gameobject

As a final step in the upgrade process I looked at what more radical changes we could make to the framework by taking advantage of Generics and some other features that C# gives us that were lacking in AS3, you can check those out towards the bottom of the readme: https://github.com/mikecann/Unity-Ash

Well that’s it for now, I hope you enjoy the improvements, please to let me know if you think its worth carrying on development, I would love to work on it some more but I have games to write!

Tinkering With Ash

Last October I was fortunate enough to attend the excellent Try Harder conference for the second time. I have spoken before about how inspirational the event is where every attendant must give a talk on something they are passionate about. One of the talks was by David Wagner’s and was on ‘The Value of Tinkering’ and it inspired me to tinker with TypeScript which led to my Recursive Chrome Extension.

Before I go any further I should mention that there is a Try Harder ‘Level Up’ session taking place in April that is open to new attendees, I thoroughly recommend you check it out!

Following on in the same ‘Tinkering’ vein I have decided to investigate an AS3 library by another Try Harder attendee Richard Lord:

logo

 

What is Ash? Well direct from the Ash Website:

Ash is a high-performance entity system framework for game development.

An entity system is a way to organise the code for a game that is efficient for both code execution and code management. It uses composition rather than inheritance for sharing features between game objects and uses a data-oriented approach to separate the game state from the game logic. This makes it much easier to manage the code and to manage the game state.

Im not going to go into the details too much of why composition over inheritance is a good idea as Richard has already done a much better job than I ever could in these two posts:

If you haven’t got a clue what im talking about when I say Entity or Component I strongly recommend checking out his posts first.

The reason why Ash has piqued my interest is because for the last three years I have been working with Entity-Component systems for games but in a totally different way. The way I have been using and developing started with the Push Button Engine (PBE) method and later expanded out to include Dependency Injection culminating in the Swft Framework.

Ill give one example of why am starting to fall in love with Ash:

In PBE and Swft the components contain data and functions. They can also declare dependencies (via [Inject]) which are automatically fulfilled when a component is added to an Entity. The functions in the component are able to act on their own data, other components and interact with the game as a whole.

One problem with this method is that components are largely tied to their entity and once attached aren’t really free be removed or added. The reason is because other component may have dependencies that depend on that component being part of the Entity. Removing the component will cause the game to crash. This becomes a problem when you want to enable a certain chunk of functionality for a certain time then disable it, what you tend to end up doing is adding the component at Entity creation time then inside of it toggling its behaviour with a boolean.

In Ash components are pure data with the bulk of the functionality being contained within systems. Sure you can have functions in a component but they only act on their own data. There are no hard dependencies between components. What this means is that components are much more free to be added and removed from Entities. So how do component function together then? Well that’s where Systems come in.

Systems are classes that contain the logic that makes up your game. When added to the engine they grab one or many lists of Nodes. A Node simply defines a collection of components that must exist on an Entity. In effect it declares the dependencies that this System needs to operate. What’s neat about this is that this list of nodes is constantly changing as components are added and removed from entities. The Ash Engine manages this all for you so all the system need do is iterate over the linked list of Nodes each frame and execute its logic.

Systems also must not declare dependencies between each other. This rule means you don’t end up with large dependency hierarchies between Systems. This frees up systems to be added and removed from the Engine with no side effects! This is rather remarkable as it lets you do crazy things that you couldn’t normally do when there are many dependencies between systems. For example your game could have a Blitting based rendering system, then halfway through a running the game you could swap that out that System and replace it with a Starling based rendering System!

Thus far I have only spent a limited amount of time tinkering with Ash but I am having a whole lot of fun. I have started work on a little game to experiment around with the framework. At the same time I have been exploring Starling, the hardware accelerated 2D rendering framework built on Stage3D. Thus far I have produced this little map editor:


Click to place a block, shift and click to remove, scroll mouse to change block type and hold control and click to zoom in / out.

Its only a tech demo at the moment and as such hasnt got any game play elements. Im not entirely sure what to turn it into but as a platform for tinkering with Ash its been great.

Its too early to share the code at the moment but if you would like to see how some Ash code looks I strongly recommend you check out Richard’s Asteroids example on GitHub. I was really quite taken aback by how neat and modular the code is. The example is provided in 4 different flavours, one using RobotLegs one with Starling one with SwiftSuspenders and one with no dependencies at all. The fact that the code still works and looks simple in all the examples really demonstrates the versatility of the framework 🙂