Roba Memo - 素人のUnity覚書と奮闘記

素人のUnity覚書と奮闘記

どっちを使うべきか・・・

キャラクターやモンスターの、歩行や攻撃といった、スプライトのアニメーションを作りたいのだけど、どういう方法を取るか悩む。

  1. UnityのAnimatorを使って、コントローラーとアニメーションを作る方法
  2. 自作スクリプトでスプライトを切り替える方法

Animatorを使う方法だと、キャラクターごとにアニメーションとコントローラーのファイルを作ることになり、かなりの数となる。
現状だと、モンスター1体に必要なファイル量はこんな感じ。
f:id:nico-taniku:20171122164629p:plain:w300

コントローラーは、こんな感じ
f:id:nico-taniku:20171122164654p:plain:w500

この矢印、1つ1つに設定を施していくのだから、かなり面倒。
そして、なにより私を悩ますのが、再生速度を速くした時など、ちょいちょい再生されずに停止してしまうこと。

その度に、この矢印部分の設定を見直しする。
いや、めっちゃ、めんどうやわ!!!

ということで、自作スクリプトにするなら、どうやるかを考えて見た。
スプライトは、1枚画像を分割して利用しているので、結構な量になる。
f:id:nico-taniku:20171122165602p:plain:h300

悶々としながら作成したスクリプトがこれ。

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

public class SpriteAnimation : MonoBehaviour
{

    SpriteRenderer render;

    Sprite[] all;
    [SerializeField] string path = "Sprites/ant";

    [Header ("後ろ向き")]
    Sprite[] idle1;
    Sprite[] walk1;
    Sprite[] attack1;
    Sprite[] skill1;

    [Header ("前向き")]
    Sprite[] idle2;
    Sprite[] walk2;
    Sprite[] attack2;
    Sprite[] skill2;

    [Header ("右向き")]
    Sprite[] idle3;
    Sprite[] walk3;
    Sprite[] attack3;
    Sprite[] skill3;

    [Header ("左向き")]
    Sprite[] idle4;
    Sprite[] walk4;
    Sprite[] attack4;
    Sprite[] skill4;

    Dictionary<uint, Sprite[]> idle = new Dictionary<uint, Sprite[]> { };
    Dictionary<uint, Sprite[]> walk = new Dictionary<uint, Sprite[]> { };
    Dictionary<uint, Sprite[]> attack = new Dictionary<uint, Sprite[]> { };
    Dictionary<uint, Sprite[]> skill = new Dictionary<uint, Sprite[]> { };


    IEnumerator ie_play;

    // Use this for initialization
    void Start ()
    {
        render = GetComponent<SpriteRenderer> ();

        all = Resources.LoadAll<Sprite> (path);
        idle1 = new Sprite[1]{ all [0] };
        attack1 = new Sprite[3]{ all [0], all [1], all [0] };
        walk1 = new Sprite[4]{ all [2], all [3], all [4], all [3] };

        idle2 = new Sprite[1]{ all [5] };
        attack2 = new Sprite[3]{ all [5], all [6], all [5] };
        walk2 = new Sprite[4]{ all [7], all [8], all [9], all [8] };

        idle3 = new Sprite[1]{ all [10] };
        attack3 = new Sprite[3]{ all [10], all [11], all [10] };
        walk3 = new Sprite[4]{ all [12], all [13], all [14], all [13] };

        idle4 = new Sprite[1]{ all [15] };
        attack4 = new Sprite[3]{ all [15], all [16], all [15] };
        walk4 = new Sprite[4]{ all [17], all [18], all [19], all [18] };


        idle.Add (1, idle1);
        idle.Add (2, idle2);
        idle.Add (3, idle3);
        idle.Add (4, idle4);

        walk.Add (1, walk1);
        walk.Add (2, walk2);
        walk.Add (3, walk3);
        walk.Add (4, walk4);

        attack.Add (1, attack1);
        attack.Add (2, attack2);
        attack.Add (3, attack3);
        attack.Add (4, attack4);

        skill.Add (1, skill1);
        skill.Add (2, skill2);
        skill.Add (3, skill3);
        skill.Add (4, skill4);

        PlayWalk (3);

    }

    public void PlayIdle (uint direction)
    {
        Debug.Log ("idle");
        if (ie_play != null) {
            StopCoroutine (ie_play);
            ie_play = null;
        }
        ie_play = Play (idle [direction], true);
        StartCoroutine (ie_play);
    }

    public void PlayWalk (uint direction)
    {
        if (ie_play != null) {
            StopCoroutine (ie_play);
            ie_play = null;
        }
        ie_play = Play (walk [direction], true);
        StartCoroutine (ie_play);
    }

    public void PlayAttack (uint direction)
    {
        if (ie_play != null) {
            StopCoroutine (ie_play);
            ie_play = null;
        }
        ie_play = Play (attack [direction], false);
        StartCoroutine (ie_play);
    }

    public void PlaySkill (uint direction)
    {
        if (ie_play != null) {
            StopCoroutine (ie_play);
            ie_play = null;
        }
        ie_play = Play (skill [direction], false);
        StartCoroutine (ie_play);
    }

    IEnumerator Play (Sprite[] sprites, bool loop)
    {
        int i = 0;

        //float speed = GameObject.Find ("PlaySpeedButton").GetComponent<PlaySpeed> ().GetPlaySpeed ();
        float speed = 1;
        speed = 1 / speed / 10;

        while (true) {
            render.sprite = sprites [i];
            if (i == sprites.Length - 1) {
                if (loop) {
                    i = 0;
                } else {
                    yield break;
                }
            } else {
                i++;
            }
            yield return new WaitForSeconds (speed);
        }
    }

}

メリットは、スクリプトで読み込みから表示までできるので、リソースに画像を置けばいいだけになる。
モンスターもキャラクターも、パターンは同じなのでスクリプトは使い回しが可能。

デメリットは、スプライトをResources.LoadAll<Sprite> (path);で一括で読み込むので、ステージに沢山のモンスターやキャラクターを配置した時の負荷が心配。

でも、Animatorは使わなくなるので、その分の負荷は軽減できるから、大丈夫かなぁ?
あぁ、どうするべきか・・・!