Working With Commands
In Yarn Spinner, you can send instructions to your game through commands. Commands look like this:
<<wait 2>>
<<setsprite ShipName happy>>
<<fade_out 1.5>>
Commands are sent to your game’s Dialogue Runner, just like lines and options are. Commands are generally not directly shown to the player; instead, they’re used for things like stage directions.
Built-in Commands
There are two built-in commands in Yarn Spinner: wait
, and stop
.
wait
The wait
command pauses the dialogue for a specified number of seconds, and then resumes. You can use integers (whole numbers), or decimals.
// Wait for 2 seconds
<<wait 2>>
// Wait for half a second
<<wait 0.5>>
stop
The stop
command immediately ends the dialogue, as though the game had reached the end of a node. Use this if you need to leave a conversation in the middle of an if
statement, or a shortcut option.
// Leave the dialogue now
<<stop>>
// Leave the dialogue if we don't have enough money
<<if $money < 50>>
Shopkeeper: You can't afford my pies!
<<stop>>
<<endif>>
Defining New Commands
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.
In Unity, there are two ways to add new commands to Yarn Spinner: automatically, via the YarnCommand
attribute, or manually, using the DialogueRunner
’s AddCommandHandler
method.
The YarnCommand
attribute
The YarnCommand
attribute lets you expose methods in a MonoBehaviour
to Yarn Spinner.
When you add the YarnCommand
attribute to a method, you specify what name the command should have in Yarn scripts. You can then use that name, along with the name of the game object that should receive that command, as a command.
For example:
public class CharacterMovement : MonoBehaviour {
[YarnCommand("jump")]
public void Jump() {
Debug.Log("Jumping!");
}
}
If you save this in a file called CharacterMovement.cs
, create a new game object called MyCharacter
, and attach the CharacterMovement
script to that game object, you can run this code in your Yarn scripts like this:
<<jump MyCharacter>>
// will print "Jumping!" in the console
You can also use methods that take parameters. For example, consider this method:
[YarnCommand("walk")]
public void Walk(string destinationName) {
// figure out the position of the object
// 'destinationName' and start walking to it
}
This command could be called like this:
<<walk MyCharacter StageLeft>> // walk to the position of the object named 'StageLeft'
You must provide as many parameters as the method expects to receive. Methods with optional parameters are supported; if you don’t provide a value for an optional parameter in your Yarn script, the parameter’s default value will be used, just like when you call the method from C#.
Supported Parameter Types
Parameters are allowed to be any of the following types:
string
integer
double
float
bool
- Any other type that implements the IConvertible interface
GameObject
Component
If a parameter is a GameObject
, Yarn Spinner will search the scene for an object whose name matches the parameter you provided. If one isn’t found, the value null
will be passed.
If a parameter is a Component
(or any of its subclasses, like Transform
or Rigidbody
), Yarn Spinner will search the scene for an object with the given name, and then look for an object of the type of the parameter. If an object with the right name can’t be found, or if it can but it doesn’t have the right component, the value null
will be passed.
Using Coroutines
You can make the Dialogue Runner wait for your commands to finish doing something before continuing. For example, you might want to have a command that makes a character walk to a point, and the Dialogue Runner should wait until that’s done.
If the method you provide is a Coroutine
, the Dialogue Runner will wait for the coroutine to finish before continuing.
Adding commands through code
You can also add new commands directly to a Dialogue Runner, using the AddCommandHandler
method.
When you call AddCommandHandler
, you provide two parameters the name of the command, and a delegate (that is, a reference to a method, or an in-line function) to run when the command is called.
The delegate can take up to 6 parameters. These parameters can be any of the supported parameter types.
For example, to create a command that makes the main camera look at an object, create a new C# script in Unity with the following code:
public class CustomCommands : MonoBehaviour {
// Drag and drop your Dialogue Runner into this variable.
public DialogueRunner dialogueRunner;
public void Awake() {
// Create a new command called 'camera_look', which looks
// at a target.
dialogueRunner.AddCommandHandler(
"camera_look",
(GameObject target) => {
// Make the main camera look at this target
Camera.main.transform.LookAt(target.transform);
// The dialogue runner will continue immediately
// after returning from this method
}
);
}
}
Add this script to any game object, and it will register the camera_look
in the Dialogue Runner you attach.
You can then call this method like this:
<<camera_look LeftMarker>> // make the camera look at an object named LeftMarker
Using Coroutines
Just as with commands you register using the YarnCommand
attribute, you can make the Dialogue Runner wait for your command to finish by using coroutines.
- If the delegate you provide returns
void
, the Dialogue Runner will continue running your code as soon as the delegate returns. - If the delegate returns a
Coroutine
, the Dialogue Runner will wait until that coroutine finishes, and then contintue running your code.
For example, here’s how you’d write your own custom implementation of <<wait>>
. (You don’t have to do this in your own games, because <<wait>>
is already added for you, but this example shows you how you’d do it yourself.)
public class CustomWaitCommand : MonoBehaviour {
// Drag and drop your Dialogue Runner into this variable.
public DialogueRunner dialogueRunner;
public void Awake() {
// Create a new command called 'custom_wait', which
// waits for one second.
dialogueRunner.AddCommandHandler(
"custom_wait",
(float duration) => {
return StartCoroutine(CustomWait(duration))
}
);
}
private IEnumerator CustomWait() {
// Wait for 1 second
yield return new WaitForSeconds(1.0);
// Yarn Spinner will now continue running!
}
}
This new method, once registered with a Dialogue Runner, can be called like this:
<<custom_wait>> // Waits for one second, then continues running
Using Methods
In addition to using delegates, you can also provide a method to the AddCommandHandler
method.
There are a couple of reasons you might want to do this: if you use a method rather than a delegate, your command can have optional parameters. Additionally, it can keep your code a little tidier, because you won’t have code nested inside function calls.
If you use a method, and that method takes parameters, you’ll need to specify their types when calling AddCommandHandler
. (You don’t need to do this when you use a delegate.)
Methods can return void
, or a Coroutine
, just like command delegates can.
For example, here’s a command that takes two parameters: a string, and an optional integer:
public class CustomMethodCommand : MonoBehaviour {
// Drag and drop your Dialogue Runner into this variable.
public DialogueRunner dialogueRunner;
public void Awake() {
// Create a new command called 'add_string_and_int',
// which logs its two parameters:
dialogueRunner.AddCommandHandler<string, int>(
"add_string_and_int",
AddStringAndInteger
);
}
private void AddStringAndInteger(string str, int i = 5) {
Debug.Log($"String: {str}, int: {i}");
}
}
This command can be run from your Yarn script like this:
<<add_string_and_int hello 1>> // logs "String: hello, int 1"
<<add_string_and_int bye>> // logs "String: bye, int 5"