Let’s get this out of the way first: I like Playmaker. Hutong Games should totally give me a freebie license of it, because I’ve made 3 out of 3 companies I worked on buy licenses, too bad it’s too late and I’ve already got one years ago. And yes, I said the Signals post was the last one in the Blood Runs Cold postmortem, but this one will include some behind the scenes as well.
Now, I know that if you search for “Should you use Playmaker in Production?” the top result is the strong negative from this post, and you’d expect a full rebuttal of that in this one. Not gonna happen: Valentin’s article actually has a lot of proper advice regarding the problems of using it in prod and you should read it. However, it falls short by having a typical engineer’s response to a designer-friendly tool that gives them a lot of power but has its caveats: “DON’T USE IT EVER!!!111one“.
How I met your toolset
It all started on my first day at Aquiris, back in 2013. Ballistic had been around for a while, and the codebase had evolved from prototype to 1.0 to 2.0, each major version having full pivots in gameplay, being developed by different groups of people with different experience levels. I was on the team that would develop 3.0, turning it from a regular team into a class based shooter.
The request was simple: someone needed to develop the new skill system, together with a visual editor for the designers to author skills. The timeline, however, wasn’t that friendly: the plan was shipping the first version in 3-4 months, along with, you know, a full metagame and UI revision, new levels and extra polish all around. Yes, gamedev in Brazil tends to be a bit hardcore.
I felt like I could probably build a half-decent editor in 3 months, but that meant I’d have almost no time to actually build the skill system and skill code itself – and that’s especially bad because I had zero knowledge about the codebase. It would, however, only take a couple of days to search if there was a ready-made solution.
(This video shows how many individual skills we ended up having. Lots of them were passive and only applied buffs, but most only triggered on specific situations, like while running, taking damage etc)
Long story short, Playmaker was the tool I picked. I chose it not because it had a little bit of code for every single possible Unity thing. It’s actually because I could throw all of that away.
In Playmaker, every state can have several Actions. Its biggest selling point was that it had pre-built Actions for everything, which meant people without any programming skills could develop their own games, start to finish. However, they also provided a simple API for you to write your own custom Actions, and that’s where the true power lies.
If you read through Valentin’s article, you’ll see all the horrible things that come with giving untamed power through a visual scripting tool. However, if you remove all of Playmaker’s builtin stuff and put it in a canopic jar somewhere and make sure that the only thing the designers have access to are your own custom built Actions, you’ve most likely reduced the entropy to manageable levels. Add to that a proper workflow and a handful of best practices, it makes leaving it in the wild sound less scary.
There are, however, some builtin Actions that are very useful and you’ll probably want to keep; usually the ones that work with flow control, like Wait (which is basically a timer) or StartFSM (which allows you to spawn other FSMs and continue the main FSM’s flow after they’re done). Depending on how savvy your designers are, you can probably also leave in some arithmetic and logical operators.
My approach is usually removing everything but a handful of those, and adding more only if really necessary – if something is even remotely tied to the game’s logic, I’ll do custom Actions for it. Granted, this is usually a pain in the ass if you have to upgrade (because even though it’s way better nowadays, Unity’s package importer is still very much manual labour), so I really wish builtin Actions were separated into category folders to make those steps easier.
Once you remove the entrails, you’ll still be left with a ton of cool stuff: visual inspection, serialization, well-performing code but, most of all, something the designers won’t be afraid to touch. And that’s most likely something that, if you were to build, it would probably take a long time to have something as polished.
You might want to build an intermediate layer to communicate between Playmaker and your code, to avoid having Actions doing a bunch of different GetComponent()s internally. I usually did that by creating a small component that would provide the FSM with access to certain parts of the code, together with an abstract custom action from which the others would inherit (that would automatically fetch that component internally). On BRC, however, we could avoid that schema by using Signals: the actions would simply dispatch them and the main systems would react.
The idea is leaving the real control outside, in your code, and Playmaker only being the visual representation of the hooks you created to those systems. This also allows you to have an IDE-friendly reference point to everything that you do – it’s hard to track down your FSMs, but it’s easy to go one step up and breakpoint your custom actions or systems. If it suits your needs and scope, you might as well just do everything on the Action code itself; just remember to try and make your Actions as atomic and specialized as possible to allow for easier reusability.
Some use cases
Ballistic’s skill system
In Ballistic, there was A LOT of logic in the skills, which meant some of them got pretty complex. There was monitoring of internal variables and branching of states based on them – we were really doing visual programming. However, not only it was me who did the first pass in all of the skills (which meant I could build the constraints along the needs), there was just a very specific subset of features that could be accessed. The code part of the skill system, turns out, was pretty similar to the one used in For Honor – only we did it before it was cool 😎
The values for buffs and debuffs were punched in directly in the FSMs, which meant rebalancing would occur in a very “sparse” manner. Having the ability to expose variables in the regular Unity inspector helped A LOT with this.
Since it was a multiplayer shooter, it also meant we had FSMs that would work locally, others that would run on the remote players, and some that would have two versions (one for actual logic and one for controlling visual effects on the remote players).
The system is still running under the hood in Ballistic Overkill.
If you have a small game, adding a bunch of if(tutorial) everywhere is fine. As soon as you have something bigger and with more entropy, you probably want to try and steer away from that. The ideal scenario is being able to completely control your game’s tutorial in parallel to the regular game code, which means that if there’s a bug caused by the tutorial, it’s a tutorial bug, not a bug on one or more features that are breaking because there’s a forgotten if(tutorial) somewhere.
Both in Legends of Honor and in BRC, the tutorials were assembled in Playmaker. In the Flash version of Legends, the tutorial was implemented via a state machine that was manually assembled in XML – unlike Unity, Flash actually seems to deal pretty well with XML, also, you know, it’s running on a PC, but sheesh, programming via XML isn’t something I’d touch with a ten foot pole.
And yes, if you hare a hammer person, everything is a nail, so it was totally “statemachine in Unity + enabling designers + short deadlines = Playmaker” in my head. However, I had a hard time convincing people that it would be cool for designers to have Unity licenses, including the designers themselves – only one of them was actually interested.
In the end it was all done and maintained by the coding team. It seemed to be a love and hate situation: some coders understood the different mindset and it was really, really easy to iterate on tutorials (and believe me, if there’s one thing tweaked over and over again on a free to play game, it’s the first time user experience), not to mention most bugs were fixed in a couple of minutes and/or an extra action. However, some people really didn’t like the approach – although the common argument against it was more towards “REAL MEN HARDCODE THEIR SHIT!” than “here’s how this could be done better” so… yeah, another (unfortunately) typical programmer trope.
Another cool thing about having this on an FSM is that the game tracking could be easily tweaked by adding intermediate steps between the logic ones. That way it was easy to verify what exactly was happening at any FTUE funnel drops.
On BRC the process was way smoother. All the designers used Unity, and multiple iterations of the FTUE were worked on solely by them. It also helped that the coding team embraced the tool and we used it for more than one system (even getting to the point where at the end of the project they thought we should have used it for more stuff).
Gameplay and Narrative
(In this section, you can see the dialogue, a call to action, the switch to a gameplay section and a little tutorial widget. All of those things are triggered by Playmaker, but run on different parts of the code)
On BRC, we considered a “gameplay session” starting a scene, playing and going back to the main menu. There were two kinds of sessions: story or freeplay. In the latter, you would simply select a scene and play based on your mastery level. On story play, you’d have several narrative “cutscenes” and would pick one or more sets of objects, sometimes with different gameplay variations. For each of the story plays we had an FSM that could be set up by the game designers and we also used FSMs for the Narrative dialogues.
Using that approach, the design team could set up 4 chapters, with an average of 20-30 story beats each, without us ever having to touch anything except helping them tweak some things or track down the odd sneaky bug. One thing I enforced strongly was no branching: we had limited dev resources and time, and I knew that we needed to work on shipping an MVP before thinking about fancy stuff. However, if they wanted to create losing conditions or branching narratives, the code was pretty much always there – I just didn’t tell anyone 🙂
Since FSMs are a single asset and inside the Playthrough FSMs we’d have several narrative dialogues, our structure used one prefab for the playthrough, and several FSM Templates for the narrative sections. That way, the designers that usually worked at the same time wouldn’t get conflicts, as they’d be dealing with different sets of assets.
For narrative specifically, there were actions for setting up a scene and for doing individual lines. In the beginning, because they were embargoed on branching, the system was perhaps a bit overkill. But as the amount of features and possibilities grew, they had access to special visual and audio effects, camera moves and even changing the backdrop completely.
Because dialogues were set up using localization keys, it would be a bit prone to human error, not to mention it was a bit of a pain in the ass to manually input them for long conversations. The narrative dept. requested a tool to automatically fill in narrative segments, but Playmaker doesn’t have a public API for their Editor.
Fortunately, I was using Rider, and it has an incredible decompiler. It took some poking around and trial and error, but I managed to build a little wizard that would spit out FSMs based on a template, which sped up their process a lot. Obviously using private external APIs is not super safe, so my second wish for Hutong would be that they provided a public API for assembling FSMs and states via code for automation tasks – with that, we could have something that would parse a marked up text and generate the first pass on an FSM, having the best of both worlds.
You’ll probably notice that in all of these examples, the usage of Playmaker was pretty localized: the state machines and their complexity were always as small as possible and dividing logic into multiple FSMs encouraged as much as possible. These are attempts to avoid having the biggest problems that you have no way around when using a tool like this: unsolvable merge conflicts and summoning not so tiny spawns of the Flying Spaghetti Monster. On the code side, there’s always the attempt to sandbox the designers in a way to mitigate risk while still giving them lots of firepower: if they have the keys to the armory, make sure you designed every weapon.
Selecting a tool that will be an integral part of development is a always a bit of a leap of faith. Even though it doesn’t come without it’s problems, Playmaker has allowed me multiple times to enable designers and focus on shipping games instead of maintenance of non-game-specific code. It’s also important to notice that it is a tool that serves a specific purpose: it’s a state-machine based visual scripting editor made to be self contained, and that’s what you’ll get, so you should only use it if that’s what you need; it’s not a behaviour tree system, it’s not engineered towards working with external dependencies, there’s no API for building state machines via code.
I’m pretty sure there might be features in it that would be useful that I don’t even know about, because the first thing I do is carve it out. Even with that, it has always had a net positive impact on the projects that I used it in – ironically, I only used it twice on personal projects.
Wearing the hat of gameplay or tools developer always has a bit of divination involved: you have to know what your designers want, what they might want and how to translate what they think they want into the things they actually do; they think in a different way than you do (they should) and you should help them doing that. Unfortunately, not everything can be read between the lines, so there’s a lot of iteration involved.
So that’s why my answer to “Should you use Playmaker in Production?” is another question, or rather, multiple questions: how much time do you want to spend making an excellent visual scripting tool that comes with serialization out of the box? Can you dedicate a team to work on it full time, like Hutong does? How much time can you invest into figuring out how to architect it in a way that blends well with Unity and feels natural to non-technical folks? Do you have anyone that reeeeally likes writing large systems using Unity’s immediate GUI (and is good at it)? Can you live with the additional problems that might come with using it? But most of all: are state machines the right tool to solve your problems?
In all the projects that I’ve used Playmaker on so far, I knew my answers to those questions. In all the others, I didn’t use it.