Commands work very similar to Yarn functions, but use a different syntax and are able to modify the game world. As a consequence of their similarity, registering custom commands is very similar to registering custom functions.
Just as with Yarn functions, registration happens when creating a DialogueRunner
. Let's again modify the example from the Quick Start:
We call the command like this:
You will have seen one crucial difference to Yarn functions immediately. The parameters are not passed in directly to the Rust function, but are wrapped in an In
struct. This is because Rust functions that are registered as commands are always valid Bevy systems. The In
parameter just tells the function which values come from the Yarn file, but we can additionally query the Bevy world as we want:
which we call like this:
The Rust functions serving as commands always require an In
parameter. If your Yarn command doesn't accept any parameters, specify the first parameter in Rust like this: fn my_command(_: In<()>, ...)
In contrast to functions, commands cannot have any Yarn facing return types. The Rust functions however can use a return value to indicate that Yarn Spinner should wait a while before continuing the dialogue. This is useful for times when you want to change something in the world before the dialogue goes on, e.g. move the camera to another speaker. To do this, simply return a type implementing TaskFinishedIndicator
, for example Arc<AtomicBool>
. This way, you can keep a copy of the Arc
and change its content to true
whenever your transition is over.
For a practical example, check out how we implement a fade out at the end of the demo.
As mentioned in the chapter Functions, Yarn can access user-defined functions. A collection of functions is called a library and can be accessed through a DialogueRunner
.
For an easy example, let's modify the code used in the Quick Start to provide a simple pow
function to Yarn:
The following snippet is of special importance:
The first parameter of add_function()
is the name of the function as seen by Yarn, "pow"
in this case. The second parameter is the Rust function that will be called in the background. Here, we reference the function definition of fn pow(...)
, but you could also register a lambda.
This pow
function can now be called from the Yarn file like this:
Which will result in the following output:
Custom functions need to follow some rules. Don't worry, they're pretty lax.
Their parameter and output types need to be primitive types or String
Parameters are allowed to be references
Parameters can have the special type YarnValue
, which stands for any input type. Additionally, functions are assumed to have no side effects. You can read the full list of requirements in the docs for YarnFn
.
Here are some examples of valid functions:
If you need functions that have side effects, e.g. for manipulating the game world, use custom commands instead.
Registered Rust functions can have a maximum of 16 parameters. If you need more, you can wrap parameters in tuples:
Tuples are treated as separate parameters when calling the function from Yarn:
Since tuples can be nested, you can use have potentially infinite parameters.
You can define your own commands, which allow the scripts you write in Yarn Spinner to control parts of the game that you've built.
Functions are units of code that Yarn scripts can call to receive a value. In addition to the built-in functions that come with Yarn Spinner, you can create your own.