ダブル餃子定食

ぎょうざの満州

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で生成します。

 

終わり

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

 

2年ゲーム制作に関わってのまとめ

この記事はCPS Lab Advent Calendar 2017の16日目の記事です。

qiita.com

 

15日の記事はこちらです。

dattiren.hatenablog.com

 

 

 

チームでゲームを作り始めて大体3年くらい経ったので発見したことなどを書きます。

僕はプログラミングが出来ない(クソ)ので技術的な記事ではありません。情報系なのにごめんなさい。でもゲームを作りたい人にとっては為になると思います。

 

 

 

軽く自己紹介をします。主に同人ゲームを作ってます。東方projectの2次創作を作ってることが多いです。

制作物は

  ・「弾けぬものなどあんまりない」http://rackpinion.jp/special/hajinai.html

   - 最新作。以下「はじない」

 ・「霊夢のくせになまいきだ。」http://rackpinion.jp/special/reinama.html

など。

制作環境は

こんな感じです。

主に2人で開発しています。僕の担当はグラフィックとサウンドです。最近ではサブでプログラミングもしています。

詳しくはHPを見ていただけると幸いです。

rack pinion

 

 

 

情報共有

始めにチーム(少数)での情報共有の話です。個人で作ろうと考えている方は飛ばして良いです。 

2人で開発をしてるのでデータに限らずアイデアなども情報共有が不可欠です。

 

Unityのプロジェクトはbitbucket、メディアはdropboxを使用します。

この体型は最新作の開発から始めたのですがUnityのgit管理が厄介でここの整備だけでかなりの時間を食いました(まだ理解出来てない部分もある)。

Unityはエディタを起動するとmetaファイルを自動で生成します。このファイルを各々のPC上で生成してしまうと現状を再現することが出来なくなります。ですので絵などのメディアを生成した後に変更をしたい場合はエクスプローラの方で上書きする必要があります。詳しいことは書きませんがとにかく大変でした。

 

ほうれんそうはDiscordを使用します。

これに関しては良く使っているからという点で使っています。良い知見があれば教えてくれると嬉しいです。

ほうれんそうの重要性は言うまでもないですね。

こまめに相談すること、こちらの意向がわかる様に丁寧に説明することが大事だと感じました。

 

 

 

ソフトについて

ただ一つ言いたいことがあります。Spineは神。以上。

ja.esotericsoftware.com

補足:まだ半年も使ってないんですが初めて触って神とわかりました。

初心者でも分かり易いUIが最高。もっと使いこなします。

 

 

 

音はゲームの重要な要素の一つです。でも録音できる環境があるわけでもないし金もない。

そこでお世話になるのがフリーの効果音公開サイトです。重宝しています。ありがとうございます。調べれば色々出てくると思います。

 

そのまま使用すると音量や雰囲気にずれが生じるのでCubaseでエフェクトを掛けます。

ゲーム制作当初は1からシンセで作っていましたが実際録音した音の方がリッチだし楽なので意図しない場合はフリー効果音を使うことをおすすめします。形式はwavです。

 

曲もCubaseを使います。ただただ作ります。

曲作りの経験がない方はフリーBGMを使うと良いかもしれません。形式はoggです。

 

※フリーの効果音やBGMを使う際は利用規則を良く読んで使いましょう。

 

 

 

ゲームシステム

チームでゲームを作る時必ず2人でゲームの根幹システムを考えます。

ゲーム制作は根幹のシステムを良い!と思えないと面白さ的にもモチベ的にも崩壊します。なのでここは頑張って練ります。

 

最新作で思った反省点があります。

良いと思ったアイデアでも開発中にシステムの問題を発見しそれを改善すると面白さが欠けてしまうことがあるというものです。

詳しく言うと当初「はじない」は”弾丸を弾く”というアイデアから制作を開始しました。しかし、開発の途中で"どうやって(プレイヤーがどのタイミングでボタンを押して)弾丸を弾くのか"、"弾くことでどの様に敵を倒すのか(ターゲッティングするか反射するだけなのか)"など問題が多発しました。

これをチームのプログラマが上手い具合に落とし込んでくれたのですが(僕には無理でした)、最終的に大雑把と言うか角の丸まったゲームになりました。

良いゲームだったのでここは悔やまれます。

これに関してはたくさん経験をしてアイデアから全体を想定できる様にならないといけないと感じました。

 

 

 

やってみなきゃわからないことが多すぎ

一番言いたかったことです。ゲームに限りません。多分なんでもそうです。

やってみてダメだったらまた別の可能性を試してみるのが最近のジャスティスであり一番難しいことです。

頭で考えているだけでやらないと口だけになります。

ゲーム制作で言うとプロトタイプを何個か作る勢いが必要だと思います。

 

さらに失敗に慣れないと次のアクションに対して腰が重くなりがちです。

結構大変なことですが良いものを作るには必要かなと感じます。

 

 

 

終わり

たった2年の若造の戯言ですいません。何かありましたらお申し付けください。

 

こうして考えや知見を文章にすると頭で整理されて良いですね。

またなんか書きたいと思いました。

 

-----

追記:制作期間ですが3年ではなく2年でした。

 

 

おわり

Twitter: fjsmu (@fjsmu) | Twitter