読者です 読者をやめる 読者になる 読者になる

いんでぃーづ

個人でゲーム開発してる上で吸収したモノたち紹介。UnityからGIMPまでなんでも。デザインとかゲーム論まで語っちゃうよ的なアレ。

MENU

Unity2D : 単体スプライトアニメーション用スクリプトの決定版を作ってみた [C#, UniRx]

{スポンサーリンク}
{スポンサーリンク}

概要

  • Unityの機能を使ったスプライトアニメーションでは、単純なものを作る場合でも余計なファイルができてしまう
  • 単体でアニメーション可能なスクリプトを組んだ
  • UniRx使用なので記述がシンプルに & Coroutine使わないので エディタ上で実行して確認可能

f:id:sugar_affordance:20170425121612g:plain

Unityでは複数のスプライトを選択してシーンにドラッグ&ドロップすれば、自動でスプライトアニメーションが設定されたオブジェクトができます。
ただこの方法だとAnimationClipとAnimatorControllerのファイルができてしまいます。

たとえば一種類のアニメーションしか使わない場合、AnimatorControllerがあるのは正直きもちわるいですね。

ということで、無駄ファイルを作成せずに一種類のアニメーションを実行するだけ&インスペクタから実行確認可能なスクリプトを作りました。

UniRxを使うことで記述がシンプルになり、さらにエディタ上で確認するのも簡単にすることができました。


目次

UniRxのインポート

まずUniRxをストアからダウンロード&プロジェクトにインポートしておきます。

https://www.assetstore.unity3d.com/jp/#!/content/17276

アニメーション用スクリプトを作成

SpriteAnimation.cs という名前で、下のスクリプトを作成します。

using System;
using System.Collections;
using UnityEngine;
using UniRx;

public class SpriteAnimation: MonoBehaviour
{
    public float fps = 24.0f;   // FPSを設定
    public Sprite[] frames;     // スプライトのリストを設定

    SpriteRenderer renderer;

    int frameIndex;

    IDisposable disposable; // 途中停止用

    public enum DefaultAction { // OnEnable時の動作指定
        None,
        Play,
        Loop
    }

    [SerializeField]
    DefaultAction defaultAction;


    void OnStart() {
        switch (defaultAction)
        {
            case DefaultAction.Play:
                Play();
                break;
            case DefaultAction.Loop:
                Loop();
                break;
        }
    }

    /**
     * アニメーション初期化
     */
    void Init() {
        Stop();

        renderer = GetComponentInChildren<SpriteRenderer>();
        renderer.sprite = null;
        frameIndex = 0;

    }

    /**
     * 一回だけアニメーション実行
     */
    public void Play() {
        Init();

        disposable = Observable.Interval(System.TimeSpan.FromMilliseconds(1000 / fps))
            .Take(frames.Length + 1)
            .Subscribe(_ => {
                if (frames.Length <= frameIndex)
                {
                    renderer.sprite = null;
                    frameIndex = 0;
                    OnAnimationFinish();
                }
                else {
                    renderer.sprite = frames[frameIndex];
                    frameIndex++;
                }
            });
    }
        
    // アニメーション終了時に呼び出す関数
    protected virtual void OnAnimationFinish() {
    }

    /**
     * ループ実行
     */
    public void Loop() {
        Init();

        disposable = Observable.Interval(System.TimeSpan.FromMilliseconds(1000 / fps))
            .Take(frames.Length)
            .RepeatUntilDisable(this)
            .Subscribe(_ => {
                if (frames.Length <= frameIndex)
                {
                    renderer.sprite = null;
                    frameIndex = 0;
                }
                renderer.sprite = frames[frameIndex];
                frameIndex++;
            });
    }

    /**
     * 停止
     */
    public void Stop() {
        if (disposable != null) {
            disposable.Dispose();
        }
        disposable = null;
    }
}

エディター上で実行するための拡張スクリプト

Assets/Editor ディレクトリを作成し、下のスクリプトを SpriteAnimationEditor.cs として保存します。

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

[CustomEditor(typeof(SpriteAnimation), true)]
public class SpriteAnimationEditor : Editor {

  public override void OnInspectorGUI(){
    if (GUILayout.Button("Play")){
      (target as SpriteAnimation).Play();
    } 
    if (GUILayout.Button("Loop")){
        (target as SpriteAnimation).Loop();
    } 
    if (GUILayout.Button("Stop")){
        (target as SpriteAnimation).Stop();
    } 
    base.OnInspectorGUI ();
  }

}

実行してみる

インスペクタからSpriteオブジェクトにスクリプトをアタッチし、下のように設定してみます。

f:id:sugar_affordance:20170425121522p:plain

Frames はアニメーションのコマ、DefaultAction はオブジェクト作成時のデフォルトの動作を設定します。

設定したら、インスペクタのPlayボタンを押してください。

f:id:sugar_affordance:20170425121612g:plain

よきかな。

Amazon.co.jpアソシエイト