Favor Small Components in Unity

Published December 03, 2015 by James Lambert, posted by HappyCoder
Do you see issues with this article? Let us know.
Advertisement

A common mistake many developers make when making their first game is trying to cram too much functionality into a single class. This violates the single responsibility principle. When designing your classes they should only do one thing and do it well. A good rule is if you need to use the word 'and' to describe what a class does, it should probably be broken up into multiple classes. There are a couple of good reasons why want to break up your classes

Small Classes Make Your Code More Reusable

By breaking down your code into smaller pieces you make it easier to reuse code. As an example, suppose you have a player class for any playable character in your game. The player can take damage so you add a damage method to the player and keep track of it health in that same class. Any attacks that hit the player you apply to the player class. Now suppose you want to make enemies able to damage each other or even have destructible environment elements. To reuse the damage code on the player you would have to bring along the rest of the player code, even if it has no place on an enemy. The other option would be to have the attacks check what type of object is being attacked and handle them separately but this makes for some messy code that is more brittle and has more bugs. A better solution would be to have a single damageable component that only handles damage as a separate class from the player.

public class Damageable : MonoBehavior 
{ 
	public float maxHealth = 100.0f; 
	private float currentHealth; 
	
	void Start() { currentHealth = maxHealth; } 
	
	public void ApplyDamage(float amount) 
	{ 
		currentHealth -= amount; 
	} 
	
	public bool IsDead 
	{ 
		get { return currentHealth <= 0.0f; } 
	} 
} 

Now you can attach this damageable component to anything you want to be able to take damage. Whenever a projectile hits an object or there is an explosion you simply apply damage to any game objects with a Damageable on it. The player, enemy, or destructible object class can simply check its own damageable to see if it is dead or not.

Small Classes Make Your Code Easier to Understand

Another benefit of making small modular pieces is they are easier to manage. You can fit the functionality of small classes in your mind all at once. This makes it easier to find bugs and to verify that the code does what you want it to. Large classes usually have lots of complicated interactions and makes it much more likely for bugs to emerge. Small modular design has been key in the development of our game, the platform rpg. We want to have many characters with unique abilities. Each ability is composed of many small and simple pieces, such as a timer class, an apply damage event class, or fire projectile class. We then compose these small pieces into more complicated abilities. A projectile doesn't have hard coded behavior when it makes contact with anything. Instead it simply fires a collided event and that event can be connected to a damage event, or any other event you want to happen when the projectile hits something.

projectile.jpg?w=1000

Since one of the main mechanics of the platform rpg is to rewind time after each player on a team it is key that the entire state of a scene can be restored to a previous time. Instead of writing code to save and restore the state of an entire ability, each small and simple piece of the ability manages saving and restoring its own state. We wrote a spell editor for the platform rpg to allow us to program visually and take a data based approach to game dev, but that is a whole other post. So if you ever find your projects falling apart because they become too hard to manage, take a close look at the design of your code. By breaking your large over-encumbered classes into smaller manageable classes you may find your entire project is easier to manage and the complexity of the project can be manageable again.

This article is reposted from Platform RPG.

Cancel Save
0 Likes 4 Comments

Comments

Gaiiden

I question the "in Unity" part of the title. Doesn't seem necessary at all

December 08, 2015 10:14 PM
HappyCoder

I question the "in Unity" part of the title. Doesn't seem necessary at all


Excellent point, since my examples were using unity and I was trying to improve SEO for my blog I included unity in the title, but I could see the argument for removing it here.
December 08, 2015 11:12 PM
snake5

The post is obnoxiously one-sided. I can easily see the counterarguments to this idea:

  • Increased number of memory allocations leads to reduced performance.
  • Amount of glue code increases due to everything being separated, which in turn also reduces perfomance and increases the complexity/unreadability of the code.
  • The amount of files to deal with while editing any object is increased.
  • Any one-off behavioral changes for certain object types require yet another file to store the derived component, thus splitting the code for special objects for many files, making editing more complicated.

Because of this, I am highly skeptical of the claim that "your entire project is easier to manage and the complexity of the project can be manageable again".
Also,

  • I see no "before" and insufficient "after" (where's the glue code?) code examples to illustrate your point and help with the credibility of your claims.
  • There is no data (and I highly doubt there will be) that could prove your point. This is fine for a blog/forum post, not for an article.
December 09, 2015 09:38 AM
All8Up

While I tend to agree with the intentions of the article, snake5 makes a good point. When it comes to Unity, components are pretty heavy weight and drag down performance when there are too many. My preferred approach is to provide utility classes which I compose into the components, instead of a lot of components. This balances the desire to maintain SRP in the primary code and maintaining performance by avoiding most of the glue needed to plug components together. But, this is of course one of those areas where each person does things their own way, I never really cared for the Unity component model due to the overhead and wanted to maintain smaller data driven systems.

December 09, 2015 01:03 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!

Having small modular classes that have well defined responsibilities makes code easier to manage and gives your more robust reusable code.

Advertisement
Advertisement