【Unity】ダメージポップアップテキストのアニメーションを実装する方法【備忘録】

# この記事は何？
RPG等でダメージを与えた(くらった)時に、頭の上に数字が出てくるタイプのダメージ表現をUnityで実装するまでの備忘録です
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291107/e2e09c25-54f8-7785-d4ec-d934c1f20212.png)

# 環境
* Unity - 2020.3.16f1 (LTS)
* DOTween Pro - Version 1.0.310
    * https://assetstore.unity.com/packages/tools/visual-scripting/dotween-pro-32416
* TextMeshPro - Version 3.0.6
    * https://docs.unity3d.com/ja/Packages/com.unity.textmeshpro@3.0/manual/index.html

※DOTweenには無料版もありますが、TextMeshProと組み合わせて使うので、DOTween Proが必要になります(令和3年8月16日現在)

# 準備
まずは、DOTweenでTextMeshProを使用するための設定を行う必要があります

以下の手順でDOTweenの設定を行います
1 : Tools > Demigiant > DOTween Utility Panel でDOTweenのユーティリティを開く
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291107/5d443aac-86e3-2cb8-0966-b5edc7bb1149.png)

2 : Setup DOTween...(add/remove Modules) ボタン押下で設定画面を開く
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291107/5a26d4f6-dee1-8e28-a255-f747efedea35.png)

3 : DOTween Pro / DOTween Timelineの中にあるTextMesh Proにチェックをする
![03.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291107/4a4997a7-9018-edcf-dca2-42902197efef.png)

4 : Applyを押して設定を反映させたら完了です

# 実装内容
## 基本
TextMeshProをアニメーションさせるためには、DOTweenTMPAnimatorを使用します

```csharp
TextMeshProUGUI textMeshProUGUI = GetComponent<TextMeshProUGUI>();

DOTweenTMPAnimator tmpAnimator = new DOTweenTMPAnimator(textMeshProUGUI);
```

## アニメーション
複数のアニメーションを組み合わせて作っていきます

### 登場
テキストが登場するまでのアニメーションには、3つのアニメーションを組み合わせています
![101.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291107/ebdc73f8-70a2-b951-b4f6-4369633eaae1.gif)

#### DOOffsetChar(int charIndex, Vector3 endValue, float duration)
1文字ごと個別に移動させます。

```csharp
TextMeshProUGUI textMeshProUGUI = GetComponent<TextMeshProUGUI>();

DOTweenTMPAnimator tmpAnimator = new DOTweenTMPAnimator(textMeshProUGUI);

for (var i = 0; i < tmpAnimator.textInfo.characterCount; i++)
{
    var charOffset = tmpAnimator.GetCharOffset(i);
    
    // 1秒かけて今いる位置からyが+5の位置に移動する
    tmpAnimator.DOOffsetChar(i, charOffset - new Vector3(0f, 5f, 0f), 1f);
}
```

#### DOFadeChar(int charIndex, float endValue, float duration)
1文字ごと個別に透明度(アルファ値)を変更します

```csharp
TextMeshProUGUI textMeshProUGUI = GetComponent<TextMeshProUGUI>();

DOTweenTMPAnimator tmpAnimator = new DOTweenTMPAnimator(textMeshProUGUI);

for (var i = 0; i < tmpAnimator.textInfo.characterCount; i++)
{
    // 3秒かけてalphaを1にする(0.0f~1.0f)
    tmpAnimator.DOFadeChar(i, 1f, 3f);
}
```

#### DOScaleChar(int charIndex, float endValue, float duration)
1文字ごと個別に大きさを変更します

```csharp
TextMeshProUGUI textMeshProUGUI = GetComponent<TextMeshProUGUI>();

DOTweenTMPAnimator tmpAnimator = new DOTweenTMPAnimator(textMeshProUGUI);

for (var i = 0; i < tmpAnimator.textInfo.characterCount; i++)
{
    // 2秒かけて大きさを3fにする(x:3 y:3 z:3)
    tmpAnimator.DOScaleChar(i, 3f, 2f);
}
```

### 消滅
![102.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291107/4901dde7-0a94-2ad6-6adf-5a76c13bcfc8.gif)

登場の際に使用したDOOffsetCharとDOFadeCharを使用しています
DoOffsetCharで上へ移動し、DoFadeCharでアルファ値を0にしています。

## アニメーションの組み合わせ
![103.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291107/95eb0102-9083-d137-5d45-e447759119d2.gif)

登場と消滅のアニメーションはDOTweenのSequenceを使用し、繋げて再生されるようにしています
Sequenceについて詳しくは👇

* [Unity] DOTweenのSequenceを使ってアニメーションを結合する
    * https://qiita.com/lycoris102/items/6a9e1e39bfa69880eaba

# 完成
ダメージポップアップテキストの完成です
![PopupDamage1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291107/4bfabe3e-48a3-44a9-87e9-3fed54d70d0b.gif)

# スクリプト
<details><summary>今回作成したスクリプト全文</summary><div>

```csharp
using DG.Tweening;
using TMPro;
using UnityEngine;

public class DamagePopupTextAnimator : MonoBehaviour
{
    [SerializeField] private TextMeshProUGUI textMeshProUGUI;
    
    [SerializeField] private float textAppearDuration = 0.15f;
    [SerializeField] private float textDisappearDuration = 0.3f;
    [SerializeField] private float textJumpHeight = 30f;

    private void Start()
    {
        textMeshProUGUI.text = string.Empty;
        textMeshProUGUI.DOFade(0, 0);
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            TakeDamage(Random.Range(1, 10000));
        }
    }

    private void TakeDamage(int damage)
    {
        textMeshProUGUI.DOFade(0, 0);
        textMeshProUGUI.text = damage.ToString();
        
        var tmpAnimator = new DOTweenTMPAnimator(textMeshProUGUI);
        
        for (var i = 0; i < tmpAnimator.textInfo.characterCount; i++)
        {
            tmpAnimator.DOScaleChar(i, 0.7f, 0);
            var charOffset = tmpAnimator.GetCharOffset(i);
            
            var sequence = DOTween.Sequence();
            
            // 登場
            sequence.Append(tmpAnimator.DOOffsetChar(i, charOffset + new Vector3(0f, textJumpHeight, 0f), textAppearDuration)
                    .SetEase(Ease.OutFlash, 2))
                .Join(tmpAnimator.DOFadeChar(i, 1f, textAppearDuration/2f))
                .Join(tmpAnimator.DOScaleChar(i, 1f, textAppearDuration)
                    .SetEase(Ease.OutBack))
                .SetDelay(0.05f * i);

            // タイミングを合わせて0.5秒待つ
            sequence.AppendInterval(0.05f * (tmpAnimator.textInfo.characterCount - i))
                .AppendInterval(0.5f);
            
            // 消滅
            sequence.Append(tmpAnimator.DOFadeChar(i, 0, textDisappearDuration));
            sequence.Join(tmpAnimator.DOOffsetChar(i, charOffset + new Vector3(0, textJumpHeight, 0), textDisappearDuration)
                .SetEase(Ease.Linear));
        }
    }
}
```

</div></details>

# おわりに
他にも色々なDO〇〇Char関数が有るので、様々なダメージポップアップテキストのアニメーションを作成できそうですね

* DOTween - Documentation
    * http://dotween.demigiant.com/documentation.php

# 参考サイト
* DOTweenでTextMeshProを文字ごとにアニメーションさせる
    * https://game-ui.net/?p=1055
* DOTween公式
    * http://dotween.demigiant.com/
* Unity Asset Store - DOTween Pro
    * https://assetstore.unity.com/packages/tools/visual-scripting/dotween-pro-32416
* TextMeshPro
    * https://docs.unity3d.com/ja/Packages/com.unity.textmeshpro@3.0/manual/index.html
* [Unity] DOTweenのSequenceを使ってアニメーションを結合する
    * https://qiita.com/lycoris102/items/6a9e1e39bfa69880eaba

# ライセンス
この記事は[ユニティちゃんライセンス条項](https://unity-chan.com/contents/license_jp/)の元に提供されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291107/c4480b31-b7b0-2e8b-75ee-b63747afa930.png)