Devlog – Every Event Needs a Queue

Sow the seeds of an ultimate score rush combo in Flower Plower!

Before adding exciting gameplay features an important question has to be answered:

How do game objects talk to each other?

One of the most important goals of software design is to reduce coupling.

Coupling occurs when the actions of one system depend on the state of another. If two objects are coupled then making changes one could result in a bug in the other. As the game grows in complexity this can lead to frustrating hours reading stack traces.

Ideally the components of the game should know nothing about each other. The tractor should have no idea what a flower is, how gravity ties it to the road or what strange force is compelling it to change direction. The tractor should sit in isolation just doing whatever tractors do.

If all the components are completely separate then how does the system handle interactions between them? How does the tractor tell the game that it just harvested a flower and scored a point if it doesn’t know what a flower is or even that its performance as a tractor is being evaluated?

This is where Software Design Patterns come in handy. This problem of code getting hairy when components meet has been suffered and studied for a long time. Some smart people have identified the problems that happen most frequently and come up with some template solutions that can solve them.

For this project I went with the Event Queue:

The specifics of my Unity implementation are somewhat different but it has the following features:

  • An Event Queue component can be added to any object and stores a list of events that happened on that frame – the list is cleared during LateUpdate (So technically it’s the events that happened last frame).
  • Objects can read or post events using an Event Queue Accessor component. The accessor component stores a reference to the event queue and actively checks rather than being notified by the queue.
  • The Event Queue does not store a reference to Event Accessor components so it will not keep them alive if they are destroyed. The accessors need to have their reference to the queue set when they are cloned at run time.

An example of how I have used it in Flower Plower would be the detection of the tractor colliding with the flower. Both these objects have a parent called ‘Farm’ with an event queue.

When the flower collider detects a collision with a harvester it puts a ‘Flower Harvested’ event on the farm’s queue. The Score and Audio system don’t need to know the specifics of the collision but they can check the farm’s event queue to find out what’s going on on the farm.

It’s a powerful idea that the Flower and Tractor can do their thing without having to report to any component except to say ‘This Happened’ to the event manager it makes it possible to combine modules in various ways. E.g. the same Tractor that is used for player control could be used in a game demo system.

It took a lot of work to prototype this important system but hopefully it will work well throughout the rest of the development.

As a reward for making it through that wall of text here’s a bonus video of some integration tests running!

Just look at those glorious green ticks.

Each test starts the game and goes through the menus before doing their thing so any weird edge-cases will be caught! My last game Spacebomb has some glitches that can make the player totally invincible so I’d like to avoid that this time.