Search icon
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Game Development Patterns with Unity 2021 - Second Edition

You're reading from  Game Development Patterns with Unity 2021 - Second Edition

Product type Book
Published in Jul 2021
Publisher Packt
ISBN-13 9781800200814
Pages 246 pages
Edition 2nd Edition
Languages
Author (1):
David Baron David Baron
Profile icon David Baron

Table of Contents (22) Chapters

Preface 1. Sections 1: Fundamentals
2. Before We Begin 3. The Game Design Document 4. A Short Primer to Programming in Unity 5. Section 2: Core Patterns
6. Implementing a Game Manager with the Singleton 7. Managing Character States with the State Pattern 8. Managing Game Events with the Event Bus 9. Implement a Replay System with the Command Pattern 10. Optimizing with the Object Pool Pattern 11. Decoupling Components with the Observer Pattern 12. Implementing Power-Ups with the Visitor Pattern 13. Implementing a Drone with the Strategy Pattern 14. Using the Decorator to Implement a Weapon System 15. Implementing a Level Editor with Spatial Partition 16. Section 3: Alternative Patterns
17. Adapting Systems with an Adapter 18. Concealing Complexity with a Facade Pattern 19. Managing Dependencies with the Service Locator Pattern 20. About Packt 21. Other Books You May Enjoy
Decoupling Components with the Observer Pattern

A common challenge in Unity development is to find elegant ways to decouple components from each other. It's a significant hurdle to overcome when writing code in the engine as it offers us so many ways to reference components through the API and the Inspector directly. But this flexibility can come with a price, and it can make your code fragile since, in some instances, it can take a single missing reference to break your game.

So, in this chapter, we will use the Observer pattern to set up relationships with core components. These relationships will be mapped by assigning objects the role of the Subject or Observer. This approach will not altogether remove coupling between our components but will loosen it up and organize it logically. It will also establish an event handling system with a one-to-many structure, which is...

Technical requirements

Understanding the Observer pattern

The core purpose of the Observer pattern is to establish a one-to-many relationship between objects in which one acts as the subject while the others take the role of observers. The subject then assumes the responsibility of notifying the observers when something inside itself changes and might concern them.

It's somewhat similar to a publisher and subscriber relationship, in which objects subscribe and listen for specific event notifications. The core difference is that the subject and observers are aware of each other in the Observer pattern, so they are still lightly coupled together.

Let's review a UML diagram of a typical implementation of the Observer pattern to see how this might work when implemented in code:

Figure 9.1 – UML diagram of the Observer pattern

As you can see, the Subject and the Observer both have respective interfaces that they implement, but the most important one to analyze is ISubject, which includes the...

Benefits and drawbacks of the Observer pattern

These are some of the benefits of the Observer pattern:

  • Dynamism: The Observer permits the Subject to add as many objects as it necessitates as Observers. But it can also remove them dynamically at runtime. 
  • One-to-Many: The main benefit of the Observer pattern is that it elegantly solves the problem of implementing an event handling system in which there's a one-to-many relationship between objects.

The following are some potential drawbacks of the Observer pattern:

  • Disorder: The Observer pattern doesn't guarantee the order in which Observers get notified. So, if two or more Observer objects share dependencies and must work together in a specific sequence, the Observer pattern, in its native form, is not designed to handle that type of execution context. 
  • Leaking: The Observer can cause memory leaks as the subject holds strong references to its observers. If it's implemented incorrectly and the Observer...

When to use the Observer pattern

The advantage of the Observer pattern is that it solves specific problems related to one-to-many relationships between objects. So, if you have a core component that often changes states and has many dependencies that need to react to those changes, then the Observer pattern permits you to define a relationship between those entities and a mechanism that enables them to be notified.

Therefore, if you are unsure when to use the Observer pattern, you should analyze the relationship between your objects to determine if this pattern is well-suited for the problem you are trying to solve.

Decoupling core components with the Observer pattern

The core ingredient of our game is the racing bike. It's the entity in our scene that changes states and updates its properties the most often as it's under the player's control while traveling around the world and interacting with other entities. It has several dependencies to manage, such as the main camera that follows it and the HUD that displays its current speed.

The racing bike is the main subject of our game, and many systems must observe it so that they can update themselves when it changes states. For instance, every time the bike collides with an obstacle, the HUD must update the current value of the shield's health, and the camera displays a full screen shader that darkens the edges of the screen to showcase the diminishing endurance.

This type of behavior is easy to implement in Unity. We could have BikeController tell HUDController and CameraController what to do when it takes damage. But for this...

Implementing the Observer pattern

Now, let's implement the Observer pattern in a simple way that can be reused in various contexts:

  1. We are going to start this code example by implementing the two elements of the pattern. Let's begin with the Subject class:
using UnityEngine;
using System.Collections;

namespace Chapter.Observer
{
public abstract class Subject : MonoBehaviour
{
private readonly
ArrayList _observers = new ArrayList();

public void Attach(Observer observer)
{
_observers.Add(observer);
}

public void Detach(Observer observer)
{
_observers.Remove(observer);
}

public void NotifyObservers()
{
foreach (Observer observer in _observers)
{
observer.Notify(this);
}
}
}
}

The Subject abstract class has three methods. The first two, Attach() and Detach(), are responsible for adding or removing an observer object from...

Testing the Observer pattern implementation

To test our implementation, we have to do the following:

  1. Open an empty Unity scene but make sure it includes at least one camera and one light.
  2. Add a 3D GameObject, such as a cube, to the scene and make it visible to the camera.
  3. Attach the BikeController script as a component to the new 3D object.
  4. Attach the CameraController script to the main scene camera.
  5. Create an empty GameObject, add the following ClientObserver script to it, and then start the scene:
using UnityEngine;

namespace Chapter.Observer
{
public class ClientObserver : MonoBehaviour
{
private BikeController _bikeController;

void Start()
{
_bikeController =
(BikeController)
FindObjectOfType(typeof(BikeController));
}

void OnGUI()
{
if (GUILayout.Button("Damage Bike"))
if (_bikeController)
_bikeController.TakeDamage(15.0f);

...

Reviewing alternative solutions

An alternative to the Observer pattern is the native C# event system. One of the significant advantages of this event system is that it's more granular than the Observer pattern because objects can listen to specific events that another emits, instead of getting a general notification from a subject.

A native event system should always be considered if you need to have components interact through events, especially if you don't need to establish a specific relationship between them.

Unity has its own native event system; it's very similar to the C# version but with added engine features, such as the ability to wire events and actions through the Inspector. To learn more, go to https://docs.unity3d.com/2021.2/Documentation/Manual/UnityEvents.html.

Summary

In this chapter, we learned how to use the Observer pattern to decouple BikeController from its dependencies by assigning them the roles of subject or observer. Our code is now easier to manage and extend as we can easily have BikeController interact with other controllers with minimal coupling.

In the next chapter, we will explore the Visitor pattern, one of the most challenging patterns to learn. We will use it to build power-ups, a core mechanic and ingredient of our game.

lock icon The rest of the chapter is locked
You have been reading a chapter from
Game Development Patterns with Unity 2021 - Second Edition
Published in: Jul 2021 Publisher: Packt ISBN-13: 9781800200814
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €14.99/month. Cancel anytime}