The Plan
Overview
In a games such as The Last of Us, authenticity and readability in the sound design is crucial, with every growl, shriek, or grunt drawing players deeper into the game world. Creatures should emit a diverse range of vocalizations that reflect their behaviours, emotions, and interactions with both the player and other creatures. Only half of this is done through asset design, with the other half coming from the implementation.
I wanted to design a system that allows creatures to behave naturally and predictably while making sure there is enough variance in their behaviour to keep a level of tension for the player. A further challenge to designing a system like this is, is making sure that these behaviours can be easily modified for a number of different creatures without having to re-invent the wheel just to alter how they react to the player as well as the world.
Code vs Blueprint
Before starting I wanted to make a decision on whether to concentrate on a C++ or Blueprint implementation. Though a combination of both is generally the best approach, especially when building an extendible and performant system, I decided to challenge myself to only use Blueprints for the following reasons :
Features
Creature properties
For the next step I wrote out a list of properties that a typical creature has. While this list could be endless, for the first implementation of a base class I concentrated on the following :
- Health – a simple float value 0 – 100
- Mood – Sedate, suspicious, raging etc.
- Status – Idle, hunting, attacking, dead etc.
Chatter
As well as the more predictable behaviours, I wanted to make sure there is a large amount of variations and randomisation in the behaviour. By having a chatter system with appropriate cooldowns and mood/status specific triggers I think it builds a far more realistic system as well as keeping players on edge.
Often this kind of creature feedback will be triggered by animations, but depending on animation and art styles, audio can often have some independence that doesn’t have to be tied to visuals.
Elements
For the sake of the prototype, I have 2 variants of a creature blueprint. Apologies for the basic models (and a little cursed!!) models, they are just to easily demonstrate the orientation of various creatures.
The creature’s main blueprint houses the creatures behaviour – not audio specific, wit all audio logic on a separate audio graph, though this should be moved to a “Creature Audio” component instead to make a more modular system allowing different people to work on different parts of of the creature simultaneously.
Basic Behaviour
By planning the basic logic in before starting in engine it’s easier to build out a prototype including most of the required events and logic as well as limiting scope.
On BeginPlay()
On MoodChange()
On StatusChange() – Handling edge cases
On MoodChange()
On MoodChange() – Handling edge cases
Distance based & line trace state changes
When a player is within a creatures “suspicious range” triggers one of the these changes of state.
When a creature enters it’s suspicious state, a line trace is enabled directly in-front of the creature for a percentage of the suspicious range.
This is an implementation I thought could be useful for triggering audio cues that are independent of animations or other systems requiring the event
DISCLAIMER – only so bunched together to get on one screen grab!
Data Table
Why use a data table?
To keep data assets separate from blueprints as it is easier for multiple people working on assets. If a designer wants to add animation triggers, they shouldn’t have to wait for a file to be free or risk a merge just to add some data.
It also makes project navigation and widespread changes later in development simpler to mitigate.
Depending on outside requirements this data table could act as the database for the all creature audio references, or just for all character vocalisation references etc.
Hard set references
Each row of the data table is an instance of a struct. The three main reference types stored in this are: Wwise events, parameters and a map. The struct can easily be expanded as requirements are changed.
Map
The map is strings (key) and wwise events (values). For references such as animation triggers it might be useful to just call unique events not shared by other creatures, without having to add references to the blueprint.
Key
This key is used to fire creature specific events by string in animations etc. Instead of a string, another asset type would make this more robust, but this is a safe option without knowing the scope of other systems.
Value
The Wwise event that will be be referenced by the key.
To Be Continued....
You made it through the basic set up, in the next post I’ll dig into the set up in Wwise and some further implementation details