複数のクラスのメソッドを指定のタイミングで同時に行う【Unity】
最近は、いろんなゲームイベントに参加しながら東京ゲームショウ アマチュア部門向けのゲームを作っていました。
先日は5/20・5/21の二日間で京都のみやこめっせで行われた
「A 5th of BitSummit」に遊びに行ってきました。
BitSummitには毎年遊びに行っているんですが、今年も面白いゲームが多く展示してあり、二日間会場を動き回りましたw
実際に制作者の方とお話することもでき、刺激を受けることが出来たので、ゲームショウに向けてゲームを作りこんでいきます。
今回の内容はタイトルにもある通り「複数のクラスのメソッドを指定のタイミングで同時に呼ぶ」です!
Expand
僕は普段Cocos2d-xを使用してゲームを作っていたのですが、今回のゲームはUnityで制作しています。
Cocos2d-xで制作をしている際、「あるタイミングで異なるクラスのメソッドを一斉に行いたい」という時に「シングルトンのmanagerクラスに、メソッドを受け渡して保存しておく」ことで解決していました。
今回はこれをUnityでも行いたいと思い実装しました。
問題の処理なのですが、Cocos2d-xで行っていた処理はこんな感じでした。
#pragma once #ifndef __Test__TestManager__ #define __Test__TestManager__ #include "cocos2d.h" //シングルトンクラス using namespace cocos2d; using namespace std; class TestManager { public: static TestManager *_instance; static TestManager *getInstance();//インスタンスを取得 bool init(); void update(float delta); void test();//登録した処理を呼ぶ処理 void addFunc(function<void()> func);//処理を登録する処理 private: vector<void()> _testFunc;//メソッド登録用の配列 }; #endif /* defined(__Test__TestManager__) */
#include "TestManager.h" TestManager *TestManager::_instance; //シングルトンにする TestManager *TestManager::getInstance() { //インスタンスが作られてなかったら作る if (_instance == NULL) { _instance = new TestManager(); _instance->init(); } return _instance; } bool TestManager::init() { // updateが毎フレーム呼ばれるよう登録 Director::getInstance()->getScheduler()->unschedule("TestManagerUpdate", this); function _update = [=](float dt) {this->update(dt); }; Director::getInstance()->getScheduler()->schedule(_update, this, 0.0f, -1, 0, false, "TestManagerUpdate"); _testFunc.clear(); return true; } void TestManager::update(float delta) { } //登録した処理を呼ぶ処理 void TestManager::test() { for (auto func : _testFunc) { func(); } } //処理の登録用メソッド void TestManager::addFunc(function<void()> func) { _testFunc.push_back(func); }
メソッドを登録したいときは、登録したいメソッドを持っている側で
function<void()> func = [=]() { log("test"); }; TestManager::getInstance()->addFunc(func);
function<void()> func = [=]() { test(); }; TestManager::getInstance()->addFunc(func);
もちろん、ここで中身にメソッドを入れてあげることで、メソッドの登録もできます。
そして、本題となるこれをUnityで実装した方法なのですが
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; public class TestManager : MonoBehaviour { public static TestManager _instance; //処理を登録するための配列 List<Action> _testFunc = new List(); void Awake() { //インスタンスが作られてなかったら作る if (_instance == null) { _instance = this; _instance.init(); } } //シングルトンにする public static TestManager getInstance() { return _instance; } bool init() { _testFunc.Clear(); return true; } void Start() { } // Update is called once per frame void Update() { } //登録した処理を呼ぶ void test() { for (int i = 0; i < _testFunc.Count; i++) { _testFunc[i](); } } //処理を登録する public void addFunc(Action func) { _testFunc.Add(func); } }
まず初めに、配列を動的に使用したいので、配列ではなくListを使用します。
Listを使用するためには、ソースコードの一番上に
using System.Collections.Generic;
//List<型> 変数名 = new List<型>(); List<int> _test = new List<int>();
そして、登録するためのメソッドの型ですが、調べたところAction型を使用することで解決できました。
Action型を使用するためにも、ソースコードの一番上に
そして、Action型を持ったListを作成します。
List<Action> _test = new List<Action>();
次に、Listにメソッドを登録するためのメソッドを作成します。
//処理を登録する public void addFunc(Action func) { _testFunc.Add(func); }
こちらにも、同じようにAction型を引数にしておきます。
Listに要素を追加する際には、Addを使用します。
あとは、登録したいメソッドを持っている側のクラスで登録します。
Action func = delegate { test(); }; TestManager.getInstance().addFunc(func);
このように宣言することで、メソッドをAction型で受け渡せるようにします。
//登録した処理を呼ぶ void test() { for (int i = 0; i < _testFunc.Count; i++) { _testFunc[i](); } }
このメソッドを実行したいタイミングに合わせて呼んであげれば、指定のタイミングで異なるクラスの処理を一斉に呼び出すことができます。
僕は、Manager側にカウンタを作ることで、数フレーム毎に呼ばれる処理などに使用しています。