Composite Pattern in Unity

James Lafritz
Dev Genius
Published in
5 min readMay 3, 2022

--

Let’s say that I want to take the complexity of my abilities to the next level.

I want a power attack ability that is a sequence ability. A Sequence Ability is an ability that has a list of abilities and Uses each ability in sequence they are in the list.

Power Attack Sequence

The Power attack will run the Heal ability, then the Rage Ability and then finally a Do Damage Over Time Ability.

The Power Attack Sequence

The Do Damage Over Time Ability is a Parallel Ability that Uses all the abilities in it’s list at the same time. It will do instant damage and delay damage.

Do Damage Over Time

What I end up with a complicated hierarchy that reuses a lot of code and allows me to put together different abilities out of component parts. To do something like this I need the Composite Pattern which looks a lot like the Strategy and Decorator Patterns.

What it is

Source: https://en.wikipedia.org/wiki/Composite_pattern

The intent of the Composite is to compose objects into tree structures to represent part-whole hierarchies. It allows me to have a tree structure and ask each node in the tree structure to perform a task. This is also how to build behavior trees. The major down side to this pattern is it is harder to restrict the type of components of a composite.

Definitions

  1. Component — Component declares the interface for objects in the composition and for accessing and managing its child components. It also implements default behavior for the interface common to all classes as appropriate.
  2. Leaf — Leaf defines behavior for primitive objects in the composition. It represents leaf objects in the composition. (It has no objects below it, like a leaf on a tree.)
  3. Composite — Composite stores child components and implements child related operations in the component interface. (Can have other objects below it, like the branches of a tree.)
  4. Client — Client manipulates the objects in the composition through the component interface.

Client use the component class interface to interact with objects in the composition structure. If recipient is a leaf then request is handled directly. If recipient is a composite, then it usually forwards request to its child components, possibly performing additional operations before and after forwarding.

Complex Abilities as the Composite Pattern

This looks something like the following.

  1. Client — Ability Runner.
  2. Component — IAbility.
  3. Leaf —Rage, Heal, Melee, Rage, other abilities
  4. Composite — Sequence, Parallel, other abilities with an array of children.
Complex Abilities as the Composite Pattern

Implementation

I need 2 different composite ability types; a Sequence Ability and a Parallel Ability.

Sequence Ability

To start I make a the Ability use the Ability Interface.

public class SequenceAbility : IAbility
{

#region Implementation of IAbility

/// <inheritdoc />
public void Use(){}

#endregion
}

To make this use the Composite Pattern I need to add an array of IAbility children.

private IAbility[] m_abilities;

of course now I need a way to set the children so I create a constructor that takes in the children as a parameter.

public SequenceAbility(IAbility[] children)
{
m_abilities = children;
}

Lastly I need to sequence through the children and Use each one.

public void Use()
{
foreach (IAbility ability in m_abilities)
{
ability.Use();
}
}
Sequence Ability

Parallel Ability

To start I make a the Ability use the Ability Interface.

public class ParallelAbility : IAbility
{
#region Implementation of IAbility /// <inheritdoc />
public void Use(){}
#endregion
}

To make this use the Composite Pattern I need to add an array of IAbility children.

private IAbility[] m_abilities;

of course now I need a way to set the children so I create a constructor that takes in the children as a parameter.

public ParallelAbility(IAbility[] children)
{
m_abilities = children;
}

Lastly I need to use all of the Abilities in parallel.

public void Use()
{
ParallelUse();
}
Parallel Ability

The Parallel Use Method Implementation is not relevant to how to implement the composite pattern.

Parallel Use Task

Power Attack

Now for the power attack ability. So I do not have to create additional ability, Damage as it is not needed to so the implementation of the Composite Pattern I am changing the Damage Ability to be the Melee Ability. I will create this ability in the Ability Runner.

The first step is to make a new Sequence Ability called powerAttackAbility. A Sequence Ability needs an array of abilities to sequence through in this case Heal Ability, Rage Ability, and Parallel Ability. The Parallel Ability needs an array of abilities to run in parallel in this case Melee Ability and Melee Ability with A Delayed Decorator.

private SequenceAbility m_powerAttackAbility = new SequenceAbility(
new IAbility[]
{
new HealAbility(), new RageAbility(),
new ParallelAbility(new IAbility[]
{
new MeleeAbility(),
new DelayedDecorator(new MeleeAbility())
})
});

Now all I need to do is Set this as the current Ability when the Button is clicked and Use the current ability;

public void SetPowerAttackAbility()
{
m_currentAbility = m_powerAttackAbility;
Use();
}

In Unity I need to make my Power Up Button Run the new Set Power Attack Ability Function when the Button is Clicked.

Power Attack in Use

Conclusion

Using the composite pattern I can create complex tree of abilities using just a few simple abilities. Notice that this code can use some work in the way the parallel use and composite use are implemented, right now I can spam the power attack and the parallel ability only runs once. The only Unity specific code here is the Ability Runner as it is a MonoBehavior, the rest is pure C#. This allows me to be able to reuse all of this in a different C# application if I wanted to.

The code can be found on Git Hub

--

--

Excited about changing my hobby into a new carer with GameDevHQ course.