Writing Custom Actions (C#)
Other than using built-in actions, you can write your own via script (C#).
Different ways to create custom actions
Since Text Animator 3.0 you can create actions in many different ways, giving you even more flexibility based on your projects needs.
Creating Actions as Components
Actions created as Components allow you to reference scene objects more easily
[System.Serializable]
class ExampleActionComponent : TypewriterActionScriptable
{
[SerializeField] float timeToWait;
// main logic here,
// ...either stateless
protected override IActionState CreateCustomState(ActionMarker marker, object typewriter)
=> new ExampleState(timeToWait);
// ...or as a Coroutine
protected override IEnumerator PerformAction(TypingInfo typingInfo)
{
// yield return ...
}
}Creating Actions as Scriptable Objects
Actions as ScriptableObjects can be reused and referenced without the need for a scene loaded
[System.Serializable]
[CreateAssetMenu(menuName = "Create Example Action")]
class ExampleActionScriptable : TypewriterActionScriptable
{
[SerializeField] float timeToWait;
// main logic here...
// ...either stateless
protected override IActionState CreateCustomState(ActionMarker marker, object typewriter)
=> new ExampleState(timeToWait);
// ...or as a Coroutine
protected override IEnumerator PerformAction(TypingInfo typingInfo)
{
// yield return ...
}
}P.S. Don’t forget to create your action ScriptableObject in the ProjectView, and add it to an actions Database.
Different ways to implement the actions logic
You can decide how to write the core logic of Actions.
Inside Coroutines (IEnumerator), or
Via a separate "tick" method (that returns if the action should keep running or if it has finished).
To start, import the correct namespaces:
using Febucci.TextAnimatorForUnity.Actions;
using Febucci.TextAnimatorCore.Typing;
using UnityEngine;Creating a coroutine
Writing a coroutine is pretty straightforward!
For example, inside your TypewriterAction class (whether it's a Component or a Scriptable), just override the PerformAction method:
[SerializeField] AudioSource source;
protected override IEnumerator PerformAction(TypingInfo typingInfo)
{
if (source != null && source.clip != null)
{
source.Play();
yield return new WaitForSeconds(source.clip.length);
}
}Creating a stateless action
Creating a Stateless action on the other hand, requires you to create a custom struct that inherits from IActionState and that will perform the action (in this case: waiting a few seconds before progressing the typewriter), like:
struct ExampleState : IActionState // <--- must inherit from this
{
float timePassed;
readonly float timeToWait;
public ExampleState(float timeToWait)
{
timePassed = 0;
this.timeToWait = timeToWait;
}
public ActionStatus Progress(float deltaTime, ref TypingInfo typingInfo)
{
// increases time passed
timePassed += deltaTime;
// tells to continue or to stop based on time
return timePassed >= timeToWait
? ActionStatus.Finished
: ActionStatus.Running;
}
public void Cancel()
{
// use this for modifying
}
}You can then instantiate this struct by overriding the CreateCustomState method inside your Action class (the one we saw here Different ways to create custom actions).
protected override IActionState CreateCustomState(ActionMarker marker, object typewriter)
=> new ExampleState(timeToWait);Attributes
The
markerparamater has useful info about your tag, for example the ID or if there are any parameters that come with it (e.g.<playSound=02>).The
typewriterreferences the Typewriter Component or AnimatedLabel that is currently performing the actionThe
typingInfocontains information such as the current typing speed (which you can modify) and time passed inside the typewriter.
Done! With this simple procedure, you can add any Custom Action you want.