ダブル餃子定食

ぎょうざの満州

Unityで2Dエフェクト管理

この記事はCPS Lab Advent Calenderの10日目の記事です。

9日目の記事は

3GIMを利用してjson形式のセンサデータをHTTPPOSTする - Qiita

11日目の記事は  

 

 前に作った「撃ち札」というゲームでのエフェクトを管理する方法です。クラス管理とエフェクトの作成方法です。なお改善点が多いので、参考程度にしてください。

 

エフェクトを管理

  • EffectManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EffectManager : MonoBehaviour {

    public static EffectManager Instance;


    private void Awake() {
        Instance = this;
    }

    public GameObject Generate(string effectName, float x, float y, float z) {

        GameObject go = Resources.Load("Prefabs/" + effectName) as GameObject;
        GameObject obj = Instantiate(go, new Vector3(x, y, z), Quaternion.identity);
        obj.GetComponent<Effect>().SetStart();
        return obj;
    }

    public GameObject Generate(string effectName, float x, float y, float z, float scaleX, float scaleY, float scaleZ) {

        GameObject go = Resources.Load("Prefabs/" + effectName) as GameObject;
        GameObject obj = Instantiate(go, new Vector3(x, y, z), Quaternion.identity);
        obj.transform.localScale = new Vector3(scaleX, scaleY, scaleZ);
        obj.GetComponent<Effect>().SetStart();
        return obj;
    }

    public GameObject Generate(string effectName, float x, float y, float z, bool se) {

        GameObject go = Resources.Load("Prefabs/" + effectName) as GameObject;
        GameObject obj = Instantiate(go, new Vector3(x, y, z), Quaternion.identity);
        obj.GetComponent<Effect>().OnSE(se);
        obj.GetComponent<Effect>().SetStart();
        return obj;
    }

    public GameObject Generate(string effectName, float x, float y, float z, float scaleX, float scaleY, float scaleZ, bool se) {

        GameObject go = Resources.Load("Prefabs/" + effectName) as GameObject;
        GameObject obj = Instantiate(go, new Vector3(x, y, z), Quaternion.identity);
        obj.transform.localScale = new Vector3(scaleX, scaleY, scaleZ);
        obj.GetComponent<Effect>().OnSE(se);
        obj.GetComponent<Effect>().SetStart();
        return obj;
    }

}

実際にエフェクトを生成するクラスです。エフェクトの名前、生成位置、サイズ、音が鳴るかどうかを設定できます。作ったエフェクトはprefabにしておいてInstantiateで生成します。シングルトンで実装しているのでカメラとか適当なオブジェクトにスクリプトを追加しておきます。

改善すべき点としてGenerate()の引数の座標やサイズはベクトル型にすべきでした。その方がスマートです。

 

  • Effect
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

interface Effect {
    void SetStart();    //init. 単発エフェクトは生成時再生開始
    void Play();    //切り替えエフェクト用
    void Stop();    //切り替えエフェクト用
    void Destroy(); //GameObject自体を削除
    float CountPlayTime();  //エフェクトの終了タイミング
    void SetColor(string st);   //色が複数あるエフェクト用
    void SetStrength(float fl); //強さがあるエフェクト用
    float GetFlgTime();    //フラグを発生させる時間を返す
    void OnSE(bool bl); //SEを鳴らすか, falseだとならない
}

エフェクトクラスはinterfaceを使用しています。これでEffectManagerはエフェクトを統一して使用することができます。

 

  • RangeAttackBliz(エフェクト例)
using UnityEngine;
using Spine.Unity;

public class RangeAttackBliz : MonoBehaviour, Effect {

    bool isRunning;
    GameObject spineAnim;
    float playCnt = 0.6f;  
    float playTime = 0f;
    float deathTime = 2.0f; 
    bool isSound = true;


    public void SetStart() {
        if (isSound)
            SoundManager.Instance.PlaySE("rangeBliz");

        spineAnim = transform.Find("SpineAnimation").gameObject;
        spineAnim.GetComponent<SkeletonAnimation>().state.SetAnimation(0, "PlaySpine", false);
        isRunning = true;
    }

    public void Update() {
        if (isRunning) {

            if (playTime >= deathTime) {
                Destroy();
            }
        }
    }

    private void FixedUpdate() {
        if (isRunning) {
            playTime += Time.deltaTime;
        }
    }

    public void Play() { }

    public void Stop() { }

    public void Destroy() {
        Destroy(this.gameObject);
    }

    public float CountPlayTime() {
        return playCnt;
    }

    public void SetColor(string st) { }

    public void SetStrength(float fl) { }

    public float GetFlgTime() {
        return 0f;
    }

    public void OnSE(bool bl) {
        isSound = bl;
    }

    public void SetNum(int num) { }
}

具体的なエフェクトを記述するクラスです。このエフェクトはspineを使用しています。他にはDOTweenで作っているエフェクトもあります。

問題はエフェクトの再生時間(playTime)や消滅させるまでの時間(deathCnt)です。エフェクトの終了がトリガーになっているシステムに使用するのですが、全て適当です。何となくです。なので冗長になったりしているエフェクトもあるのでこれは何か他の解決策を考えなければと思います。

またSEを設定できる様に設計していますが、ここにまとめるべきではなかった様に思えます。これはイベントまで時間がなかったのでこんな風になってしまいました。SEはSoundManager.Instance.PlaySe("rangeBliz")で鳴らしています。

 

  •  Main(呼び出すクラス)
using UnityEngine;

public class Test : MonoBehaviour {

    GameObject obj;
    
    private void Start() {
        obj = EffectManager.Instance.Generate("RangeAttackBliz", 0f, 0f, 0f, 1f, 1f, 1f);
    }
}

 これでEffectManagerのGenerateで生成します。

 

終わり

これでだいぶ簡単になりました。ですが最初にも書きましたがまだまだ改善点も多いです。次回使うときはもっと洗練させたものにしたいです。