Skip to content
第10回 メッシュとシェーダーによる斬撃

4 / 4 斬撃の再生と終了状態 ​

このステップの目的

表示位置と濃度を時間へつなぎ、一度表示して消える動作を確認します。

再生用コンポーネント ​

前のステップのSlashを使います。ScriptsフォルダーへCrescentSlash.csを作り、次の全文を記述します。第08回と同じく、経過時間を0〜1へ変換してカーブを読みます。

MaterialPropertyBlockは、このRendererに渡す値を保持します。元のMaterialを書き換えず、同じMaterialを使う別の斬撃へ異なる値を渡せます。Shader GraphのReferenceと、コードの_Phase・_Speed・_Intensityを一致させてください。

csharp
using UnityEngine;

[RequireComponent(typeof(MeshRenderer))]
public class CrescentSlash : MonoBehaviour
{
    [SerializeField, Min(0.01f)] private float lifeTime = 1f;
    [SerializeField] private float speed = 1f;
    [SerializeField] private AnimationCurve phaseCurve = AnimationCurve.Linear(0f, 0f, 1f, 1f);
    [SerializeField] private AnimationCurve intensityCurve = AnimationCurve.Linear(0f, 1f, 1f, 0f);

    private MeshRenderer meshRenderer;
    private MaterialPropertyBlock properties;
    private float elapsed;
    private bool playing;

    private void Awake()
    {
        meshRenderer = GetComponent<MeshRenderer>();
        properties = new MaterialPropertyBlock();
    }

    private void OnEnable() => Play();
    private void OnDisable() => Stop();

    private void Update()
    {
        if (!playing)
            return;
        elapsed += Time.deltaTime;
        float t = lifeTime <= 0f ? 1f : Mathf.Clamp01(elapsed / lifeTime);
        Apply(phaseCurve.Evaluate(t), intensityCurve.Evaluate(t));
        if (t >= 1f)
            Stop();
    }

    [ContextMenu("Play")]
    public void Play()
    {
        if (!Application.isPlaying || meshRenderer == null)
            return;
        elapsed = 0f;
        playing = true;
        Apply(phaseCurve.Evaluate(0f), intensityCurve.Evaluate(0f));
    }

    [ContextMenu("Stop")]
    public void Stop()
    {
        playing = false;
        if (meshRenderer != null)
            Apply(phaseCurve.Evaluate(0f), 0f);
    }

    private void Apply(float phase, float intensity)
    {
        meshRenderer.GetPropertyBlock(properties);
        properties.SetFloat("_Phase", phase);
        properties.SetFloat("_Speed", speed);
        properties.SetFloat("_Intensity", Mathf.Clamp01(intensity));
        meshRenderer.SetPropertyBlock(properties);
    }
}

Consoleを確認してから、SlashへCrescent Slashを追加します。Life Time 1、Speed 1、Phase Curveの端点(0,0) → (1,1)、Intensity Curveの端点(0,1) → (1,0)を確認します。

再生・停止・再生し直し ​

  1. Playし、光が弧に沿って進んで1秒後に消えることを確認します。
  2. Play中にCrescent Slashコンポーネントのメニューを開き、Playを選びます。同じ始点から再生します。
  3. Life Timeを5へ変えて再びPlayを選び、途中で同じメニューのStopを選びます。途中の位置で光が残らず消えることを確認します。
  4. もう一度Playを選び、再生できることを確認します。コンポーネントを無効・有効にした場合も確認します。
  5. SceneのPlayを終了し、Life Timeを1へ戻します。Intensity Curveの最後の値は0を維持します。

このコードは終了時にGameObjectを削除しません。非表示で残して、次のPlayで再利用します。途中停止ではカーブの途中値にかかわらずIntensityを0にします。

調整と提出 ​

Life Timeを固定し、Phase Curveの途中に(0.2, 0.6)を追加すると、前半に大きく進む動きになります。基準の直線と比較してから復元し、採用する動きを決めます。ノイズを止めた比較が必要なら、Crescent Slash側のSpeedを0にします。再生中の値はこのコンポーネントが上書きするため、Material側のSpeedでは変更できません。

SlashをPrefabとして保存し、Sceneへ再配置してPlayします。元のSlashと二重にならないよう一方を無効にし、同じ見た目を再現できることを確認します。

チェックリスト
  • 一度再生して消え、途中停止でも描画が残らない。
  • 再生し直すと同じ始点へ戻る。
  • PhaseとIntensityを分けて説明し、変更前後の画像または動画と調整理由を提出できる。