Skip to content
第08回 数字の表示とアニメーション

2 / 4 数字の生成と一度の再生 ​

このステップの目的

数字の内容を渡して再生し、表示時間が終わると消える状態を作ります。

数字が受け持つ処理 ​

前のステップのDamageNumberを使います。Assets/UNSLOW/EffectPractice/ScriptsへDamageNumber.csを作り、次の全文に置き換えます。このコンポーネントは、表示内容を受け取るSetupと、再生中の表示を更新するUpdateを持ちます。

elapsed / lifeTimeは、秒で進む時間を開始時0、終了時1へ変換します。AnimationCurve.Evaluate(t)は、その時点に対応するカーブの高さを取り出します。Y方向の移動量はUIの単位、Scaleは元の大きさに掛ける倍率、Alphaは元の透明度に掛ける割合です。

csharp
using TMPro;
using UnityEngine;

[RequireComponent(typeof(TextMeshProUGUI))]
public class DamageNumber : MonoBehaviour
{
    [SerializeField, Min(0.01f)] private float lifeTime = 1f;
    [SerializeField] private AnimationCurve moveCurve = AnimationCurve.Linear(0f, 0f, 1f, 80f);
    [SerializeField] private AnimationCurve scaleCurve = AnimationCurve.Linear(0f, 1f, 1f, 1f);
    [SerializeField] private AnimationCurve alphaCurve = new(
        new Keyframe(0f, 1f), new Keyframe(0.5f, 1f), new Keyframe(1f, 0f));

    private RectTransform rect;
    private TMP_Text label;
    private Vector2 startPosition;
    private Vector3 startScale;
    private Color startColor;
    private float elapsed;
    private bool playing;

    private void Awake()
    {
        rect = GetComponent<RectTransform>();
        label = GetComponent<TMP_Text>();
        startPosition = rect.anchoredPosition;
        startScale = rect.localScale;
    }

    public void Setup(string message, Color color)
    {
        label.text = message;
        startColor = color;
        elapsed = 0f;
        playing = true;
        Apply(0f);
    }

    private void Update()
    {
        if (!playing)
            return;

        elapsed += Time.deltaTime;
        float t = lifeTime <= 0f ? 1f : Mathf.Clamp01(elapsed / lifeTime);
        Apply(t);
        if (t >= 1f)
            Destroy(gameObject);
    }

    private void Apply(float t)
    {
        rect.anchoredPosition = startPosition + Vector2.up * moveCurve.Evaluate(t);
        rect.localScale = startScale * scaleCurve.Evaluate(t);
        Color color = startColor;
        color.a *= Mathf.Clamp01(alphaCurve.Evaluate(t));
        label.color = color;
    }
}

Consoleにコンパイルエラーがないことを確認し、DamageNumberへ同名のコンポーネントを追加します。ProjectのPrefabsフォルダーへドラッグしてPrefabを保存し、Scene上の数字を削除します。Prefabは有効な状態で保存してください。以降は、再生時にこのPrefabから数字を生成します。

生成する側の準備 ​

同じScriptsフォルダーへDamageNumberPreview.csを作ります。ゲームのダメージ計算に代わり、授業ではこのスクリプトから固定値を渡します。

csharp
using UnityEngine;

public class DamageNumberPreview : MonoBehaviour
{
    [SerializeField] private DamageNumber numberPrefab;
    [SerializeField] private RectTransform canvasTransform;
    [SerializeField] private int value = 120;
    [SerializeField] private bool recovery;
    [SerializeField] private Color color = Color.white;

    private void Start()
    {
        DamageNumber number = Instantiate(numberPrefab, canvasTransform);
        string message = recovery ? $"+{value}" : value.ToString();
        number.Setup(message, color);
    }
}
  1. 空のGameObjectをNumberPreviewとして作り、DamageNumberPreviewを追加します。
  2. Number PrefabへProjectのDamageNumber、Canvas TransformへHierarchyのCanvasを割り当てます。
  3. Valueを120、Recoveryを無効、Colorを白・Alpha 1にします。
  4. Playすると数字が中央に現れ、1秒で上へ移動して消えます。Hierarchyでも生成された数字が削除されることを確認します。
  5. Playを終了して、もう一度Playします。同じ開始位置から再生されれば成功です。

表示されないときはConsoleのエラー、二つの参照、Prefabが有効か、Canvasの表示方式を確認します。Sceneに数字が残っていた場合は、Prefabから生成されたものと二重になっていないかも確認してください。

チェックリスト
  • Start → Instantiate → Setupの順で内容が渡ることを説明できる。
  • Playし直すと同じ位置から現れ、表示時間後に削除される。