# 编写自定义效果（C#）

除了使用 [内置效果](/text-animator-unity/3.x-zh/xiao-guo/nei-zhi-xiao-guo-lie-biao.md) 或 [从检查器创建自定义效果](/text-animator-unity/3.x-zh/zi-ding-yi/chuang-jian-ni-zi-ji-de-xiao-guo.md), <mark style="color:默认;background-color:$warning;">**你也可以通过 C# 轻松编写自定义效果**</mark>.

{% hint style="info" %}
附注：确保你已阅读 [高级概念](/text-animator-unity/3.x-zh/bian-xie-zi-ding-yi-lei/gao-ji-gai-nian.md) 页面！
{% endhint %}

效果有三个关键部分（可以写在同一个文件中）。

<table data-view="cards"><thead><tr><th></th><th></th></tr></thead><tbody><tr><td><strong>参数类/结构体</strong></td><td>包含有关你将在效果中使用的数据/值的信息（<strong>状态）</strong> </td></tr><tr><td><strong>状态</strong> 结构体</td><td>主效果类。根据参数和字符，随时间修改它。同时处理 <a data-mention href="/pages/fcf4f88b28b49780d39777586af51e7613cd2ba5">/pages/fcf4f88b28b49780d39777586af51e7613cd2ba5</a></td></tr><tr><td><strong>可脚本化封装</strong></td><td>将前面的元素统一在一起并让你将内容保存到磁盘。只需几行代码让我们完成其余工作！</td></tr></tbody></table>

{% hint style="success" %}
这些名称只是约定，但 **你可以按自己喜欢的方式命名它们**!

只要知道你需要：&#x20;

* 用于存储效果变量的东西
* 负责修改字母的结构体
* 将这两者黏合并允许你将信息保存到磁盘的可脚本化对象
  {% endhint %}

## 编写你的自定义脚本

{% hint style="info" %}
在本示例中，我们制作了一个使字符按可变量上升的效果。
{% endhint %}

首先，确保导入必要的命名空间（你的 IDE 无论如何都会提示你 <3）

<pre class="language-csharp"><code class="lang-csharp">using UnityEngine;

// 导入 Text Animator 的命名空间
<strong>using Febucci.TextAnimatorCore;
</strong>using Febucci.TextAnimatorCore.Text;
<strong>using Febucci.Parsing;
</strong><strong>using Febucci.TextAnimatorForUnity.Effects;
</strong></code></pre>

### 参数

创建你将用来修改字符的数据（这就是你将在检查器中看到并编辑的内容）。

```csharp
// 可以是 struct 或 class
// 后者允许你拥有默认值
[System.Serializable]
class CustomEffectParameters
{
    public float amount = 1.5f;
}
```

### 状态

效果的“核心”部分。根据参数和预先计算的 Text Animator 数据修改字母。

* 该结构体必须继承自 **IEffectState**.

```csharp
// 必须是 struct！
struct CustomEffectState : IEffectState
{
    readonly float defaultAmount;
    float amount;


    public CustomEffectState(CustomEffectParameters data)
    {
        // 从参数类获取默认量
        this.defaultAmount = data.amount;
        this.amount = defaultAmount;
    }

    public void UpdateParameters(RegionParameters parameters)
    {
        // 自动处理用户在富文本标签中写入的情况， 
        // 在此例中为 "a"
        //（例如 <tagID a=5> 会将 "amount" 设为 5，而 
        // a*2 会使 "amount" 成为 defaultAmount 的两倍）
        amount = parameters.ModifyFloat("a", defaultAmount);
    }

    public void Apply(ref CharacterData character, in ManagedEffectContext context)
    {
        // 使用 "amount" 将字符向上移动
        // 使用清晰且易用的 API
        character.MovePosition(
            Vector3.Up * amount * context.progressionRange * context.intensity,
            context.isUpPositive
            );
        // 1. 注意 context.progressionRange -> 它是 
        //     你在编辑器中分配的曲线！
        //     允许你得到阶跃、正弦、弹跳等效果
        // 2. 还要注意 context.intensity，需用于实现 
        //     阶段之间的平滑过渡。
        }
}
```

### 可脚本化对象封装

创建将你的自定义效果挂接到 Text Animator 所需的逻辑，并将其保存在 Assets 文件夹中。

```csharp
[System.Serializable] // <-- 使其可序列化！！
[CreateAssetMenu(fileName = "Your Custom Effect")]
class CustomEffectScriptable : ManagedEffectScriptable<CustomEffectState, CustomEffectParameters>
{
    // 简单地根据参数（已由 text animator 管理）创建一个新状态
    protected override CustomEffectState CreateState(CustomEffectParameters parameters)
        => new CustomEffectState(parameters);
}
```

{% hint style="info" %}
还有另一个接受更多类型的 "ManagedEffectScriptable" 版本，以及 "Referenced" 效果的实现，但我们将在未来的版本中介绍！
{% endhint %}

{% hint style="success" %}
这些脚本是 Text Animator 确保你获得以下内容所需的全部：

* 自动管理的曲线、播放、修饰符
* 无竞态条件的优化效果
* 兼容 AOT 平台的效果（无需使用反射）
* 我们强大的预览编辑器
* 在 UI Toolkit 和 Text Mesh Pro 上表现一致的效果，包括动态缩放

还有更多！<3
{% endhint %}

<figure><img src="/files/8ca187870ae1d1cb61e8da138ef9afe353e471d0" alt=""><figcaption></figcaption></figure>

***

{% hint style="success" %}
完成！  **你已完成所有必要步骤，耶！**\
你添加的效果越多，这个过程就越熟悉、越简单。
{% endhint %}

{% hint style="warning" %}
记得为你的效果在检查器中设置标签并将其添加到数据库！否则它将无法被识别。你可以在这里阅读更多： [效果数据库](/text-animator-unity/3.x-zh/xiao-guo/ru-he-tian-jia-xiao-guo/xiao-guo-shu-ju-ku.md)
{% endhint %}

**祝你在应用效果时玩得开心！**

***

{% hint style="info" %}
关于创建 “Referenced” 效果的指南即将推出，因为我们仍在调整 UX/API 部分。
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.febucci.com/text-animator-unity/3.x-zh/bian-xie-zi-ding-yi-lei/bian-xie-zi-ding-yi-xiao-guo-c.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
