Flyweight Pattern
This is a useful way to separate the data from the logic.
The flyweight pattern is an easy way to optimize code, and make your designers’ lives much easier by centralizing data. For example, you have ten instances of an NPC with a maxHP, movement speed, and delays for their movement. Would it be better for each of them use memory to hold onto these static stats, or would it be better if they all just reference the same object containing all the data? In all the projects I’ve worked on, the latter was the better option.
Having the properties centralized using a scriptable object proved to be useful because whenever the designer wanted to change the properties they knew they only needed to go to one place to change values and it will apply to all instances of the . A bonus to using the flyweight pattern with scriptable objects is that you can change values in runtime and it will persist when you stop the editor.
Ultimately, having all the data centralized makes it easier to track and add new features to it so that we only need to track one reference for each object.
Example:
In this example from a prototype for an encyclopedia for a client, it shows different characters that move around a map. They each have their stats stored in a scriptable object which gets passed to an encyclopedia manager that shows their stats. You can see the stats being used by a movement script by the different speeds the characters move, and by the stats displayed in the encyclopedia entry.
State Machines
I found state machines useful for managing behaviours of objects in-game.
The most common problem it solves for me is that it allows us to easily modify behaviours by tracking specific game states during runtime. For example, by combining a state machine with the observer pattern we are able to manage player controls and enemy behaviours depending on whether the game is currently in a paused, playing, or in a cutscene state.
To manage this I create a manager interface that handles states and a listener interface that will be dynamically add themselves to the manager and will be notified of changes.
This can also be scaled down to a version that doesn’t require listeners and relies on game events. I use this scaled down version to manage instance states such as enemy behaviours.
Example:
In this example from another prototype, it shows the different game states at play. The states are as follows:
Default: The player is able to move around the world using WASD and start aiming.
Aiming: The player is no longer able to move, and is able to aim using the same WASD controls and cast the line.
Hooking: Once the lure hits the water, the fish change their local state from using a ‘Wander’ behaviour to an ‘Alert’ behaviour and move closer until they can bite at the lure.
Reeling: Once a fish is hooked, they move to a ‘Fight’ state where they try not get reeled in by the player. The gamestate also cause the UI to change to show the reeling UI. Within the fish’s ‘Fight’ state they also move from pulling, to resting, to being tired as indicated by the icons above the fish.
Catching: Once the fish gets reeled in towards the player, the caught fish is displayed before the game state moves back to the ‘Default’ state.