Events, actions, and reactions are the foundation of many games - story driven or not. You could say that the gameplay itself is the foundation - and you would be right - but it is also the goal of the gameplay to toggle these events and reactions. In the context or this DevBlog an event could include opening a treasure chest, opening a door, toggling the camera to follow a platform that moves from point A to point B, or even running through an entire in-engine cinematic. There are numerous ways of handling these in game development. Some games use scripting systems to handle these events such as Python, Lua, or even C#. Other games - such as A Purrtato Tail - use a visual programming interface. The majority of Purrtato itself is programmed in C#, however writing code to handle numerous simple little events would actually take far more time, and be much less efficient, to program in C#. Therefore, we have integrated a visual programming interface for Unity known as playMaker.
Developed by Hutong Games, playMaker is a simple to use graph-based visual programming system that is flexible, easy to expand, and easy to integrate - yet tremendously powerful. The main concept of playMaker - or really any visual scripting system - is the ability to rapidly construct a node-based graph with potential branching options. Each graph has an entry point, and may or may not terminate its actions. For A Purrtato Tail, we needed a way to rapidly generate potentially thousands of micro-events to handle things like opening doors or flipping switches along with lots of complex cinematic sequences. After review of various options, it just made sense to go with playMaker.
Let's take a look at a simple playMaker graph as used in A Purrtato Tail. Throughout the game, we have Levers - or as they are called in the code, ScenerySwitch. A ScenerySwitch is a child of our primary master object class, SceneTriggerZone, which is pretty much exactly what it sounds like - 2D box based trigger zones that do 'something' when the player is inside of them. The parent SceneTriggerZone handles all the heavy lifting of knowing if the player is in zone, what is the active TriggerZone (if there are multiple in range), and so forth, allowing the child classes such as ScenerySwitch to focus on their very specific actions. In the case of a ScenerySwitch, those actions recognize that the player is inside the zone, and listens for if the Use action button is pressed.
Your standard every-day paw powered lever.
A lever of course could do all kinds of things! It could toggle a door to open, or turn on a machine. We needed a way to allow both a way to manage the state manipulation of the switch (On, Off, etc.) along with being able to build upon this to have more complex events. We turned to playMaker to help us construct exactly that, and built a Lever playMaker graph which exists on all Lever prefabs. The main Lever playMaker Graph looks like this...
Simply enough - when the playMaker graph is enabled, the Start node is toggled, which then goes into State 1. It then sits on State 1 and waits until the TurnedOn or TurnedOff flags are changed. When one of those changes, it moves the active Node ahead to the appropriate Node, which itself some Actions that control what happens when that Node is entered. It then transitions into ResetValues, which informs the ScenerySwitch object that the Turn On / Turn Off action has completed, and then returns to State 1 to wait for the state to change again. The result of this is - you turn on the switch, and the Turned On node can open a door, then wait for it to be finished opening before Resetting the values and giving the player the ability to pull the switch again - or lock the switch in place so it cannot be pulled again.
These Actions that each Node have are essentially just Unity Components, but very specialized to be used in playMaker. in the above Graph, the Start 1 node has a single Action - the Switch Watcher Action, which looks like this:
TurnedOn and TurnedOff are the different paths that this graph will take when the switch is either Turned On, or Turned Off.
That's a simple lever, but how about something a bit more complex - such as a cinematic? For those who have played the game introduction, you remember the crucial scene where the ceiling collapses and Pixel is taught how to connect characters to Fur Static to create platforms. Well, this is what that exact scene looks like in playMaker...
Quite a lot more happening here! Let's step through it and see what all those nodes are doing:
- The event is setup, with all the initial objects in their starting positions.
- Wait for the player to enter the trigger zone.
- Wait for the game to be in a place that the event can start - IE: make sure the player is not attacking, is not in the air, is not in any menus, etc. This helps us to prevent sequence-breaks. Once we are in a good position, the game enters Event Mode - which is a state that the player cannot do anything, and the event itself is now controlling what happens. At points the player might be allowed to press a button, but otherwise the game is in full control.
- Disable the door triggers! A little sneaky, but this just makes sure the player can't leave the event in the middle of it.
- Handle the actual collapse of the ceiling - moving the ceiling to the new position, masking out damaged objects, playing sound effects and particle systems, etc.
- Wait a moment...
- Then drop some debris for detail.
- Now we begin the dialog itself. Dialog Handlers are separate objects in the scene that have a number of ways they can be triggered. In the case of this one, the triggering is handled through playMaker.
- Listen for the conversation dialog to be completed.
- End the event. This takes the game out of Event Mode, and gives the player control once again. Notice we do not end the actual event yet however!
- Here we give the player their first collectible character - the Spud Soldier. This sets the state flag that the player has found the character, and displays the Got Character animated dialog.
- Wait for the Got Character dialog to be closed.
- Show a Hot Tip to tell the player to select their newly acquired character.
- Wait for the character to be selected.
- Wait for the character to be placed.
The remaining 2 nodes - Final Dialog and Final Action Watcher - these are just safety nodes. Notice how they loop back to previous nodes? This allows the game to watch for if the player has backtracked in the steps, such as dropping the character back into the menu before placing them. These 2 watchers then let us jump back to the step the player is actually on. And finally, Done - just tells us that everything is completed!
As you might be thinking - that seems like WAY more Actions than Nodes! Well, a single Node can do multiple Actions. For the above Graph, here is what the Actions for the Wait for Purrtato to be Selected Node looks like:
Show a tip to the player, and handle 2 potential Game Piece actions which handle moving to different Nodes as appropriate.
Phew - okay, that was quite a bit beefier. But you can probably tell just how much faster that is to build in a visual programming system than it would be to build ALL OF THAT in code. This alone could be days if not weeks of programming to handle all the little nuances, but thanks to visual scripting in playMaker - we can build this in a couple hours. And many of the Actions that these nodes control can be entirely custom - in fact, A Purrtato Tail currently has 87 (yes, 87) custom playMaker Actions that can quickly control and manage our numerous custom systems and gameplay elements. These custom Actions are used in conjunction with the already numerous Actions that ship with the playMaker system.
Let's look at one more playMaker graph. This is from an event in the unreleased upcoming demo - The Caterwauling of Cantermow - where the player can place bomb objects to blow up caverns, resulting in ending a pair of waterfalls from flowing.
Rather than stepping through this one with you - why don't you see if you can figure out what's going on here? It is a pretty simple event, but still has a lot going on to make it smooth and seamless. Post your ideas on what this is doing on Twitter or in our Discord and let's see how close you can get!
So those were Events. A Purrtato Tail is loaded with little and large events, and playMaker controls each and every one. Rather than weeks of development for every event, it's a matter of hours - or even minutes. And many of these events can be prefabbed and reused, potentially even with slight adjustments to turn them into entirely new events. Nearly every video game has events of different kinds - what are some of your favorite events, or if you're a developer how do you prefer to manage them? Let us know on Twitter or in our Discord!