LoginSignup
2
2

More than 3 years have passed since last update.

Unityのアニメーションイベントで引数にScriptableObjectを渡す

Last updated at Posted at 2020-03-08

アニメーションイベント

新しい「タイムライン」機能ではなく、昔からあるアニメーションクリップについての話題である。
Unityのアニメーションクリップには任意のフレームで関数を呼び出す機能がある。
関数の引数はint, float, string, Enum, AnimationEvent, GameObject参照が1つだけである。
https://docs.unity3d.com/jp/540/ScriptReference/AnimationEvent.html

アニメーションと同期してなにか処理したいときには非常に便利な機能だが、呼び出せる引数の個数は1つで型もあまり自由にできるわけではない。
ゲームオブジェクト(プレハブなど)を渡すこともできるが、これはこれで大層である。そこで、ScriptableObjectを渡すことができれば、データ構造として多数の情報を引き渡し、なおかつGameObjectのように余計なものは付いてこないので良さげである。
早速試してみたところ、期待した動作になっていたのでここに記載する。

実装

なにかゲームオブジェクトを配置してAnimatorControllerを取り付け、AnimationClipを作成しておきます。
コメント 2020-03-08 205621.png

以下のスクリプトも取り付けます。アニメーションから呼び出される関数を引数タイプごとに作成しています。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class testobj : MonoBehaviour
{
    public enum TestEnum
    {
        ONE, TWO, THREE
    }
    // Start is called before the first frame update
    void Start()
    {
    }
    // Update is called once per frame
    void Update()
    {
    }
    public void Func01(int _arg)
    {
        Debug.Log($"int:{_arg}");
    }
    public void Func02(float _arg)
    {
        Debug.Log($"float:{_arg}");
    }
    public void Func03(string _arg)
    {
        Debug.Log($"string:{_arg}");
    }
    public void Func04(GameObject _arg)
    {
        Debug.Log($"GameObject:{_arg.name}");
    }
    public void Func05(TestEnum _arg)
    {
        Debug.Log($"Enum:{_arg}");
    }
    public void Func06(AnimationEvent _arg)
    {
        Debug.Log($"AnimationEvent float:{_arg}");
    }
}

AnimationClipにイベント設定します。
コメント 2020-03-08 195434.png

各イベントをInspectorで見てみるとこんな感じ。
int
コメント 2020-03-08 200239.png

float
コメント 2020-03-08 200258.png

string
コメント 2020-03-08 200320.png

Enum
コメント 2020-03-08 200342.png

GameObject(Prefab)
コメント 2020-03-08 200409.png

AnimationEvent
コメント 2020-03-08 200433.png

実行するとConsoleに結果が表示されます。
コメント 2020-03-08 204719.png

ScriptableObjectを使う

まずはScriptableObjectをつくる。

using System;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu]
public class EventData : ScriptableObject
{
    [SerializeField] private int intdata;
    [SerializeField] private float floatdata;

    public int Intdata { get => intdata; set => intdata = value; }
    public float Floatdata { get => floatdata; set => floatdata = value; }
}

クラスの宣言時に[createAssetMenu]を書くことでEditorで簡単にScriptableObjectが作成できる。
コメント 2020-03-08 234237.png

こうしてイベントとして引き渡したい情報を設定したScriptableObjectを作っておく。

コメント 2020-03-08 234526.png

イベントとして呼び出す関数を追加。引数にはScriptableObjectの型を指定する。

     :
    public void Func07(EventData _arg)
    {
        Debug.Log($"EventData Int:{_arg.Intdata}");
        Debug.Log($"EventData float:{_arg.Floatdata}");
    }
     :

AnimationClipにイベントを追加。EventDataのところには作成したScriptableObjectをドロップすることができる。
コメント 2020-03-08 234810.png

実行結果

コメント 2020-03-08 234955.png
無事にデータが引き渡せた。

Githubで公開
https://github.com/sokude/UnityAnimationTimelineAndScriptableObject

使い所例

私がこのパターンを使った例は、シューティングゲームの敵機を実装したときでした。敵の移動の軌跡はAnimationClipでPositionとRotationを変化させていき、弾を撃ちたいところでイベント呼び出しています。このとき、弾撃ちのバリエーションごとに関数を作ってられないので、複数の情報を渡したいと考えて使ってみました。弾撃ちの方向と個数、開き角、スピードなどの情報をまとめたScriptableObjectを作成し、イベントでそのオブジェクトを引き渡し弾を撃たせることができました。
もっとも、あらかじめScriptableObjectを作っておかないといけないので、バリエーション増やす手間はかかります。完全にアニメーション上で設定できるわけではないのですが、シューティングゲームの弾撃ちバリエーションくらいならこの方法で対応は可能かと。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2