Component Model Race Condition Solutions

October 4th, 2010| Posted by Andy Korth
Categories: Uncategorized | Tags:

Last week I talked about Unity’s Component model. I pointed out some problems, and this week, I have some possible solutions- each with some downsides.

Order your entities: In a homebrew component system, you can simply order your entities, and order the list of components within them. Now you have explicit control over execution order. Once you understand the race conditions, (which always takes a bit of work), you can order your code appropriately and manually. There’s a lot of information to hold in your head about order dependencies, and you have a pretty fragile system. This fragility isn’t specific to component based systems, but it’s harder to deal with. Reordering entities is kind of a poor solution, since it’s error prone (easy to introduce code or reorder entities in a way that fixes one problem but breaks another), hides complexity (you don’t know which orderings are significant, or which are coincidental- since everything must be in the ordered list), and can take a lot of time to manage. It’s a very conceptually simple solution, and is probably most effective with a large number of developers that can brute force bugs away.

Adopt some lazy loading solutions: We’ve taken this approach to some degree. If our TitleScreen component starts music and relies on the MusicManager initialization code being run, simply accessing the MusicManager creates the singleton instance of the class and initializes it. This can be handy since different parts of the game all might require the music loaded first. You can start the game on Level 4, bypassing the title, and the music manager will still initialize itself when you try to play a song. On the other hand, we’ve used this methods to create circular dependencies. In Unity, specifically, certain components or gameobjects might not exist to be referenced or lazily loaded when you want to do this. This is a Unity specific problem that centers around differences between their Awake and Start methods and how objects are added to the scene.

Create a dispatcher of sorts: In Unity, there’s a one-to-one relationship between your classes and components. Good programmers have a learned notion of what belongs in a class, and when it’s time to put code in a new class. While you can make classes that aren’t components in Unity, you will find yourself pushed to make unconscionable design decisions to fit your pegs into Unity’s holes. After all, if Unity provides a entity and component framework, you should use it, right? If you’re willing to sidestep some of the component system, you can create a sort of dispatching system. In Unity, a manager or dispatcher would simply have a list of other components- it’ll go through that list and call initialization methods one after another. This could kind of suck if you have to make a different initialization manager for each scene- since you’ll have different key components in each scene. The advantage is that you only need to worry about order sensitive components.

Dynamic Dispatcher: Annotate each critical component with a “priority” number. Sort all these components by priority and run methods on them in that order. Don’t worry about simple scripts that can run whenever. Difficulties arise when components are reused. Someone essentially did just this, and we were thinking of doing something similar.

However, there are some additional challenges in pragmatic situations. On Wednesday, I’ll mention how these challenges have affected our decisions in real Unity games.

Comments are closed.