VARIABLE SETUP
Now that you have created your first unit, we are going to teach you the next step. Coroutines!
If you ever intend a unit to do work over time, this is the perfect tutorial for you. In this tutorial we will be creating something that you can actually use in your projects, instead of a throwaway unit. This unit will be a Type Writer unit. You will be able to display one extra character every X amount of seconds until it is fully written out.
To start, we will setup our variables just like last time. What will we need?
A port to start the coroutine. We will use an actual method for this one, instead of a lambda.
An exit for right after we start the coroutine.
A complete port for when the typing is done.
An input value of string for the text we want to write.
An input float for the time delay between each character.
An output string value port for the current text written.
And a storing variable for the current text that we will feed out to the current text port.
We won't go over the basics here, so we assume you understand how that can be setup. You should have the following:
using
Ludiq.Bolt;
using
Ludiq;
using
UnityEngine;
public class
TypeWriterUnit
:
Unit
{
[
DoNotSerialize
]
public
ControlInput
start;
[
DoNotSerialize
]
public
ControlOutput
exit;
[
DoNotSerialize
]
public
ControlOutput
typed;
[
DoNotSerialize
]
public
ControlOutput
complete;
[
DoNotSerialize
]
public
ValueInput
text;
[
DoNotSerialize
]
public
ValueInput
delay;
[
DoNotSerialize
]
public
ValueOutput
current;
private
string
storedText =
string
.Empty;
protected override void
Definition()
{
}
}
Now that we have the setup lets define all the ports before we get to the logic.
When you have a coroutine, the input that runs one, must use an input coroutine instead of a normal input. There is a similar input method like ControlInput, but called ControlInputCoroutine.
This is setup in the exact same way as other inputs, except the 2nd parameter.
Normally we would do:
Func<Flow, ControlOutput>
Instead it becomes:
Func<Flow, IEnumerator>
Which the IEnumerator is necessary for all Unity Coroutines.
using
Ludiq.Bolt;
using
Ludiq;
public class
TypeWriterUnit
:
Unit
{
[
DoNotSerialize
]
public
ControlInput
start;
[
DoNotSerialize
]
public
ControlOutput
exit;
[
DoNotSerialize
]
public
ControlOutput
typed;
[
DoNotSerialize
]
public
ControlOutput
complete;
[
DoNotSerialize
]
public
ValueInput
text;
[
DoNotSerialize
]
public
ValueInput
delay;
[
DoNotSerialize
]
public
ValueOutput
current;
private
string
storedText =
string
.Empty;
protected override void
Definition()
{
start = ControlInputCoroutine(
"start"
, WriteText);
text = ValueInput<
string
>(
"text"
,
string
.Empty);
delay = ValueInput<
string
>(
"delay"
, 0.2f);
current = ValueOutput<
string
>(
"current"
, (flow) => {
return
storedText; });
typed = ControlOutput(
"typed"
);
complete = ControlOutput(
"complete"
);
exit = ControlOutput(
"exit"
);
}
private IEnumerator
WriteText(
Flow
flow)
{
}
}
Now that we are setup, lets generate the unit. This is what you should have:
This is the last step and you are on your way. We must create the behaviour for the routine to occur. First we should cache our input values when we first enter the unit. So lets get and set our startingText, time, and count. The count will be used to determine what the current length of the string is. A string is also an array of characters, so we can use it to iterate over it, using the current count.
private IEnumerator
WriteText(
Flow
flow)
{
var
startingText = flow.GetValue<
string
>(text);
var
_delay = flow.GetValue<
float
>(delay);
var
count = 1;
}
Next, we know we will need to exit immediately before we ever start looping. A Flow itself, is yieldable as an enumerator, so yield the exit port in order to keep the output as a coroutine itself, allowing nestable routines.
private IEnumerator
WriteText(
Flow
flow)
{
var
startingText = flow.GetValue<
string
>(text);
var
_delay = flow.GetValue<
float
>(delay);
var
count = 1;
yield return
exit;
}
We're now going to create the most important step, the loop!
Each loop count, we will assign the storedText class variable using SubString. This allows us to grab a section of the full text, based on the current count. From '0', the first character, to 'count', which is the last character. This variable is what we are using to send to the output. That is important.
After that we want to yield our output 'typed' port, wait X amount of seconds, then add another count, and repeat. All this will occur until the storedText is equal or greater then the length of the startingText value. Afterward, we will yield the complete port, and then we are done coding!
private IEnumerator
WriteText(
Flow
flow)
{
var
startingText = flow.GetValue<
string
>(text);
var
_delay = flow.GetValue<
float
>(delay);
var
count = 1;
yield return
exit;
while
(storedText.Length < startingText.Length)
{
storedText = startingText.Substring(0, count);
yield return
typed;
yield return new
WaitForSeconds
(time);
count++;
}
yield return
complete;
}
We are all set. Last thing to do is set it up in the graph. We will debug the text to make sure it is working properly. Don't forget, in 1.4 your start event should be checkmarked 'Coroutine' in the graph inspector. Here is what your final result should look like: