# Writing Custom Actions (C#)

Other than using [built-in actions](https://docs.febucci.com/text-animator-unity/typewriter/wait-actions-when-typing), you can write your own via script (C#).

{% hint style="info" %}
Be sure to read the [advanced-concepts](https://docs.febucci.com/text-animator-unity/writing-custom-classes/advanced-concepts "mention") page as well.
{% endhint %}

***

## Different ways to create custom actions <a href="#actions-base-class" id="actions-base-class"></a>

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

{% hint style="success" %}
Actions created as Components allow you to reference scene objects more easily
{% endhint %}

```csharp
[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

{% hint style="success" %}
Actions as ScriptableObjects can be reused and referenced without the need for a scene loaded
{% endhint %}

```csharp
[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 ...
    }
}
```

{% hint style="warning" %}
P.S. Don’t forget to create your action ScriptableObject in the ProjectView, and add it to an actions Database.
{% endhint %}

***

## Different ways to implement the actions logic <a href="#actions-base-class" id="actions-base-class"></a>

You can decide how to write the core logic of Actions.&#x20;

* 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:

<pre class="language-csharp"><code class="lang-csharp"><strong>using Febucci.TextAnimatorForUnity.Actions;
</strong><strong>using Febucci.TextAnimatorCore.Typing;
</strong>using UnityEngine;
</code></pre>

### Creating a coroutine <a href="#actions-base-class" id="actions-base-class"></a>

Writing a coroutine is pretty straightforward!&#x20;

For example, inside your TypewriterAction class (whether it's a Component or a Scriptable), just override the PerformAction method:

```csharp
[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 <a href="#actions-base-class" id="actions-base-class"></a>

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:

```csharp
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 [#actions-base-class](#actions-base-class "mention")).

```csharp
protected override IActionState CreateCustomState(ActionMarker marker, object typewriter)
        => new ExampleState(timeToWait);
```

### Attributes <a href="#attributes" id="attributes"></a>

* The `marker` paramater 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 `typewriter` references the Typewriter Component or AnimatedLabel that is currently performing the action
* The `typingInfo` contains information such as the current typing speed (which you can modify) and time passed inside the typewriter.

***

{% hint style="success" %}
Done! With this simple procedure, you can add any Custom Action you want.
{% endhint %}
