# 커스텀 효과 작성(C#)

사용하는 것 외에도 [내장 이펙트](/text-animator-unity/3.x-ko/effects/built-in-effects-list.md) 또는 [인스펙터에서 직접 커스텀으로 만드는 것](/text-animator-unity/3.x-ko/customization/create-your-own-effects.md), <mark style="color:기본값;background-color:$warning;">**C#을 통해 커스텀 이펙트를 쉽게 프로그래밍할 수 있습니다**</mark>.

{% hint style="info" %}
추신. 반드시 읽었는지 확인하세요 [고급 개념](/text-animator-unity/3.x-ko/writing-custom-classes/advanced-concepts.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/396018f42ad39412c7e70d16eb5306b764543c5b">/pages/396018f42ad39412c7e70d16eb5306b764543c5b</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)
    {
        // 파라미터 클래스에서 기본 amount를 가져옵니다
        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가 관리함) 단순히 새로운 State를 생성합니다
    protected override CustomEffectState CreateState(CustomEffectParameters parameters)
        => new CustomEffectState(parameters);
}
```

{% hint style="info" %}
"ManagedEffectScriptable"의 더 많은 타입을 허용하는 다른 버전과 "Referenced" 이펙트 구현이 있지만, 이는 앞으로의 버전에서 다룰 예정입니다!
{% endhint %}

{% hint style="success" %}
이 스크립트들은 Text Animator가 다음을 보장하기 위해 필요로 하는 전부입니다:

* 자동 관리되는 커브, 재생, 수식자
* 경쟁 상태(race condition) 없는 최적화된 이펙트
* 리플렉션을 사용할 필요 없는 AOT 플랫폼과 호환되는 이펙트
* 강력한 미리보기 에디터
* 동적 스케일링을 포함해 UI Toolkit과 Text Mesh Pro에서 동일하게 작동하는 이펙트

그리고 더! <3
{% endhint %}

<figure><img src="/files/0defbe3c2ceafbd0375cd503a836f3d1893a7855" alt=""><figcaption></figcaption></figure>

***

{% hint style="success" %}
완료!  **필요한 모든 단계가 완료되었습니다, 야호!**\
이펙트를 더 많이 추가할수록 이 과정은 더 익숙하고 단순하게 느껴질 것입니다.
{% endhint %}

{% hint style="warning" %}
인스펙터에서 이펙트에 태그를 지정하고 데이터베이스에 추가하는 것을 잊지 마세요! 그렇지 않으면 인식되지 않습니다. 자세한 내용은 여기에서 읽을 수 있습니다: [효과 데이터베이스](/text-animator-unity/3.x-ko/effects/how-to-add-effects/effects-database.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-ko/writing-custom-classes/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.
