This is a review of Bolt. a visual scripting plugin for Unity. The plugin has been developed and published by Ludiq.
With Bolt you create flowgraphs to create logic for your game. The goal of the plugin is to make it easier for non-programmers to be able to write game logic. Making it a potential tool for less programming oriented people in your team such as artists and designers. You may have heard of similar tools, such as Blueprints for Unreal. But also Playmaker and Flowcanvas.
The goal of this review is to explain the base functionality of Bolt and how it works. And to give my own opinion on how well it can accompany someone that is already used to C# in Unity. Finally I will also perform some performance benchmarks in this review. In order to properly test this plugin and give a fair review of Bolt I decided to create a sample project called “Happy Flappy”. This sample project will be made available in the future on the Unity Asset Store. This sample project has a C# version as well as a Bolt version.
One of the unique aspects of Bolt visual scripting is that it uses reflection to get references to C# code in your project. What reflection means is that it, scans through all the code in the project to see what it can talk to. This makes it easy to call C# methods from Bolt, eliminating the time-cost to create custom nodes to interface between Bolt and C#. However, it is harder to communicate towards Bolt then the other way around, and using reflection does have a performance cost.
You can clearly see that the user experience of the plugin has been heavily influenced by the Blueprinting system from Unreal Engine by epic games. Which is a good thing.
This is an affiliated link, by purchasing this plugin you will support me. Helping development of new games & products!
Usability – Getting started
Getting started with the plugin is very easy. You get a startup prompt asking you to configure the plugin. You can choose to view the nodes in a human like-naming scheme or a programming scheme.
After these selections you get the option to select your assemblies. This is useful if you have any external plugins that are distributed as a DLL. Allowing you to use them using Bolt visual scripting.
A lot of plugins do have source code tough, meaning that they will get placed in Assembly-CSharp-firstpass. Meaning that if you have new plugins or C# code you would only have to update the Unit Options in Tools/Bolt/Update Unit Options.
After the setup is complete, you dont a lot of guidance on what to do next within the engine itself. It may have been cool to see a create your first graph button, or to have sample bolt graphs, example one that implements basic movement. However it does display Manual and Support buttons that bring you to useful pages on the website. It is also worth mentioning that there are a couple of free sample projects available
In order to get started, you create an empty Game Object. And Add Component> Bolt> Flow Machine. And afterwards on the component you press new, this asks you to create a new .asset file. Which is called a Flow Macro.
Getting started is quite straightforward. Instead of creating C# files you create .asset files which contain the instructions required. Getting started with Bolt feels very streamlined and premium.
Usability – Finder
In order to start implementing logic you can easily find nodes using the finder.
Which can be toggled using Right Click.
The scanning of the search bar is fast enough and takes 1-2 seconds at best (depending on the scale of your search) using a I7-8700K upon the first search. If you do the same search again it will be instant. This means searches get cached after you have performed them.
I’ve tested if it persists after (stored in the library folder of a project) when you restart Unity. It seems like this is not the case, but I wouldn’t consider that an issue.
Usability – Configuring your graphs
Bolt allows you to name and give a summary for each graph you make. Allowing you to keep the project organised
Control/Value input and outputs are meant to be used for Super Units. These units are meant to be callable like functions. I will get to these later, as they can be useful to avoid a lot of repetition.
As you can see, Bolt supports variables of various scopes. Starting with the most local, to the entire application. With the addition of saved variables.
It is worth mentioning that, when you add a existing flow graph to an object, no variables get declared. So it may be wise to make use of prefabs, in case you want to reuse functionality. In my opinion it would be nice to have a “Auto generate feature”. So it would fill in the Variables component automatically based on the requirements of a graph.
Being able to declare global variables within the App or Scene can be useful for smaller applications. However I can imagine that it can become messy when the game starts to scale up. I would personally recommend creating multiple scenes for multiple purposes In case you go for a bigger scale game with Bolt. So you would have one scene for the Player and Camera. One for global user interface, one for the game interface. Etc. Else you may have to start working with a very big list of variables over time.
Usability – Live editing
This is one of the greatest strengths of Bolt. You are able to edit graphs while the game is running. Or even add new nodes while it is running. Meaning you can prototype functionality very quickly.
Usability – Communication between Bolt and C#
Bolt has the upper hand in terms of communication. There are limited options when it comes to calling functionality in Bolt from C#. Most of it is the other way around, meaning you can call any public function you make in C# from Bolt. But it isn’t possible to call all event node from C#. Altough to be fair, there is little reason to call those things from C#, since you want optimal performance.
One of the options for calling Bolt code is by triggering custom events.
The sample below shows you how to do this.
using Ludiq;
using Bolt;
CustomEvent.Trigger(targetGameObject, argument1, argument2, ...)
Usability – State machines
Super units are useful if you have a graph that you want to use multiple times. A super unit is just a regular Flow Graph, with the Inputs and Outputs configured. I personally think it’s great that Bolt has this feature, since having to repeat yourself isn’t good practice. In the second picture, you can see how the Super Unit of the first picture is used.
Usability – Communicating between graphs
When you make games, it is often useful to decouple scripts to keep your code/graphs flexible and extendable. As far as I know events are the one and only way of doing this at the moment in Bolt. In order to use events, you have to call the Custom Event node.
In order to use events, you have to call the Custom Event node. There are some things you may have to keep in mind when using Custom Events tough:
KEEP IN MIND: Events only get triggered based on the target you set for them.
In the case of the nodes below, the event will only be called flow graphs that are on the same Game Object. So this would not call any flow graphs that listen for the event.
Solution: Use a global object in the scene, or app and use that as a target. Unless you intend to just use the event trigger within the same graph.
KEEP IN MIND: Usage of strings is more prone to human error
Mistakes happen, sometimes there may be a space, an incorrect capital letter or any other small issue. My recommendation is to store the strings as variables, and just reference those variables instead.
EXTRA: You can also call events as a coroutine. This means you can run a method that takes a certain amount of time. Just tag it as a coroutine and use the Next Frame node (Wait one frame) or the Wait For Seconds node.
Usability – State machines
Bolt also features usability of state machines. The sample game I made does not make use of them. But from my understanding it you to hook up multiple flow graphs and move between them based on a transition condition. Similar to how the Animator does transitions.
A graph will call “On Enter State” after it has switched to that state. In the example above It will run a coroutine in a while loop indefinitely and wait 1-4 seconds each tick. I’m assuming it automatically cancels the coroutine once the transition has been exited.
Performance – Startup Time & Plugin Size
Performance is a big consideration when using a plugin. In this example I will be taking a look at the startup time of the plugin, testing it on builds of several devices.
using UnityEngine;
using UnityEngine.UI;
public class StartupTimeCheck : MonoBehaviour
{
[SerializeField] private Text text;
void Start()
{
text.text = Time.realtimeSinceStartup.ToString();
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
Application.Quit();
}
}
Startup time tests have been conducted without the splash screen using Unity 2019.1.7f1 and Bolt version 1.4.9 NET4. These packages have been included during testing the empty projects, so the total size could be reduced even more. Above all I’m most interested in the size and startup speeds that Bolt adds.
Please do note that the results vary per device, and they only serve as a indicator.
The application size increase is very acceptable in my opinion. With it adding just about 3.1 mb for the IL2CPP build. And less for the Mono Build. Of course, the acceptability does depends on the kind of application you are making.
Building with Mono takes a big performance hit in terms of startup speed on mobile, in contrast to IL2CPP. While on PC it is less of an issue. Also, for users that do not use Unity Plus or Pro. The splash screen itself takes time, allowing for a couple of seconds of loading. Resulting in a bit more leeway in terms of noticeable slowdown with boot time. During my tests the game started right away after the splash screen faded out.
Performance – Code Performance
Since Bolt uses Reflection, you can expect performance overhead.
Therefore I decided to run some tests to share with you. Giving you an indication of the potential performance cost of using Bolt instead of C#.
private void Start()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine($"C# Test - {CSharpTest()}");
sb.AppendLine($"Bolt Self Log - {RunBoltTest("TestSelfLog")}");
sb.AppendLine($"Bolt Iterate - {RunBoltTest("TestIterate")}");
sb.AppendLine($"Bolt Pure - {RunBoltTest("TestPure")}");
text.text = sb.ToString();
}
public string CSharpTest()
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 10000; i++)
{
var length = Vector3.Distance(new Vector3(1, 4, 6), new Vector3(3, 25, 66));
}
sw.Stop();
return sw.Elapsed.TotalMilliseconds.ToString();
}
private string RunBoltTest(string eventName)
{
Stopwatch sw = new Stopwatch();
sw.Start();
CustomEvent.Trigger(boltObject, eventName);
sw.Stop();
return sw.Elapsed.TotalMilliseconds.ToString();
}
As you can see from the code above, I’m applying a simple distance check between two vectors using Vector3.Distance(v1,v2). The tests are done using the Stopwatch class and the StringBuilder class to create a string to read the results from. As a result this made it possible for me to read the results from any target device.
As seen above, there is a significant performance cost of using Bolt, in comparison to C#. I’ve also tested the results by using a C# stopwatch, but the results were about the same as using the Stopwatch class in Bolt. Based on these results it is safe to say that it is wise to write more expensive methods and systems in C#.
When comparing the C# call from Bolt to the direct call, there is little difference in terms of milliseconds. Whereas the direct C# call for “Android Mono” has a speed of 3.9 milliseconds, and the Bolt call has 4 milliseconds. The IL2CPP one has an increase of 0.01 milliseconds. This indicates that a single C# call from Bolt doesn’t apply a real effect on the duration of a frame. The difference falls in margin of error.
Bolt 2.0
You can expect Bbolt to be released in 2020. Early versions are already obtainable. Bolt 2.0 will be a free update. As you can see on the image below, it has a vertical alignment instead of horizontal. Seemingly this has the potential to produce less “Visual Spaghetti”. However that remains to be seen. Aside from the visual changes there is a very important change “C# Code Generation”. Meaning you will be able to use visual scripting in Unity without a performance loss. As a result you can have the best of both worlds when working on your game, being able to live edit your game. And then after you want to make a build, you let it generate all C# code for you.
Conclusion
After having created the “Happy Flappy” prototype in both C# and Bolt. I can say that I prefer C# more, this is mainly because of my own speed of using C#. Personally, for me it is just faster to write it down in code.
Some things are just a lot quicker to type in C# then in Bolt. One example of this is including simple calculations in a function call. In Bolt you would have to get a separate node, with multiple connections to enter a calculation. Although, if you are proficient with Bolt, it can still be done quickly.
What I do like about Bolt is that you can literally turn your Bolt graph into C#. This makes it straightforward to optimize a Bolt project. It could actually serve as a bridge towards using and learning C#, since you are coding in a visual manner. I can imagine it takes away the scariness of using code for new users, instead giving users a feeling of a sandbox they can play with.
Is Bolt a good fit for your project?
For medium sized games I can imagine Bolt being useful for simple systems that do not execute each frame. For instance for a dialogue system. Or for small one time actions that do not warrant having a custom made component.
If your main intent is to use some kind of graph system, and you want a bare bones node solution where you can script high performance nodes yourself. Then xNode is a viable consideration for you opposed to Bolt. However, Bolt could prove to be useful to actually prototype such a node based system before you write the nodes in C#.
Small games are a good fit for Bolt. Because it helps you iterate quickly, and those types of games are generally very lightweight in terms of coding requirements. Getting 60 fps from your games with Bolt is certainly a possibility, but it isn’t going to be easy for bigger projects unless you use C# as well. Consequently I would personally not dare making a bigger sized project with just pure Bolt. You can make bigger projects with Bolt, just don’t expect the best performance for now. I’m sure Bolt 2.0 will be a life changer in this regard. Despite the performance issues, Bolt is a great plugin and has a good premium feel to it.
Thanks, helped a lot
Very informative. Contain information that helped me understand if Bolt is the tool I’m looking for.