
【Unity】非同期式の入れ子処理で遅延のない時間監視を実現する
2020.08.14
目次
非同期式制御を用いてゲーム内の時間を監視しよう!
今回は、ゲームを作る上で必要になってくる「制限時間の監視」について紹介したいと思います。
Unity における時間計測の方法は、いくつかあります。
1つ目は、VisualStudioなどのコンパイラにデフォルトでついている「ヘッダーを使う方法」。
2つ目は、「専用のアセットを使う方法」です。
拡張性の問題
この「専用のアセットを使う方法」ですが、もちろん質のいいアセットをインポートして使うことが出来れば良いのですが、それではあまり拡張性がありません。
「時間に合わせて自作のゲージを動かしたり」、「ゲーム上のキャラクターの動きに時間を反映させたり」する場合などは、拡張性が理想的ではありません。
他のオブジェクトに時間を戻り値として返す時に、返すタイミングや型などに、制限がついているためです。
時間計測、監視が出来ない問題
また、通常の時間計測、監視の構文を、 void Start(){} や void Update(){} の中で動かしてしまうと、正しい時間計測、監視が出来ない原因となります。
同じ関数の中で動いている構文に、処理時間を費やされたり、メモリを消費されたりしてしまうためです。
今回はそういった遅延が起きないよう、非同期式の入れ子処理で、遅延のない、時間計測、監視の開発していきたいと思います!
開発における注意点
- Unity の ver は「2018 3.14f1」です。2019など、他の年の ver ではエラーが出ることがあります。
- VisualStudio などの情報は2020年3月10日現在のものです。
- 最終的にはアセットなどを一切使わないのでインストールの必要はありません。
こちらの記事もオススメ!
一番シンプルな時間計測「非同期式制御」で開発
では早速、「非同期式制御」を用いて遅延のない時間計測、監視の開発をしてみようと思います。
「同期式制御」と「非同期式制御」
まず、「同期式制御」とは、通常の void Start(){} や void Update(){} 文の中で、コードに記載された順番ごとにひとつひとつ処理していくことをいいます。
それに対し、「非同期式制御」は void Start(){} や void Update(){} の中ではない「コルーチン」という方式で関数のようなものを定義します。
その「コルーチン」を void Start(){} や void Update(){} の中に書かれているコードとは別系統で動作させます。
このような形式で動かしているので、他のコードによる処理の影響を受けづらく、遅延のない時間計測を実現できます。
4秒待つだけの制御のコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | void Start() { StartCoroutine("Limittime"); } // Update is called once per frame void Update() { } IEnumerator Limittime() { yield return new WaitForSeconds(4); } |
非常に短いですね。
IEnumerator Limittime() で、関数のように「コルーチン」を定義しています。
そして、 void Start(){} で StartCoroutine("Limittime"); を用いて定義した「コルーチン」を呼び出しています。
using について
スクリプト冒頭の using の部分は、下記のようにスクリプトを作った初期状態のままです。
1 2 3 | using System.Collections; using System.Collections.Generic; using UnityEngine; |
拡張性を生かして制限時間やライフのゲージを表現する
では、次はスクリプトを加工して、ライフゲージを作っていきましょう。
今回は、以下の画像のように、6つのハートの3Dオブジェクトを消していくことで表現していきます。
ソースコード
空のゲームオブジェクトに、以下のようなコードをアタッチします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | using System.Collections; using System.Collections.Generic; using UnityEngine; public class RedeffectCTRL2 : MonoBehaviour { public GameObject heart1, heart2, heart3, heart4, heart5, heart6; // Start is called before the first frame update void Start() { StartCoroutine("Limittime"); } // Update is called once per frame void Update() { //こちらにメインのゲームの処理を書く。 } IEnumerator Limittime() { yield return new WaitForSeconds(4); heart1.SetActive(false); yield return new WaitForSeconds(4); heart2.SetActive(false); yield return new WaitForSeconds(4); heart3.SetActive(false); yield return new WaitForSeconds(4); heart4.SetActive(false); yield return new WaitForSeconds(4); heart5.SetActive(false); yield return new WaitForSeconds(4); heart6.SetActive(false); } } |
「入れ子」と配列を用いてコードをシンプルに
このままでも十分に遅延の対策はできています。
ですが、先ほどの例の場合、ハートの数がとてつもなく多くすると、スクリプトが長くなってしまいます。
しかし、コルーチンの中で「for文」や、「while文」を回しても元も子もないので、「入れ子」を使っていこうと思います。
入れ子とは
「入れ子」というのは、自分自身の関数を、その関数内で呼び出すことをいいます。
木構造のデータ配列の解析や、ヒープソートなどを行うときにも用います。
同期式制御の関数ではなく、非同期式制御でのコルーチンを使っているので、コルーチンの中でコルーチンを呼び出しても処理速度に影響はありません。
ソースコード(元のソースコードをコメントで表示)
次のコードでは、入れ子の場合とそうでない場合を比較するために、元の場合をコメント文で表示しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | using System.Collections; using System.Collections.Generic; using UnityEngine; public class RedeffectCTRL2 : MonoBehaviour { public GameObject eff; public static int i; // public GameObject heart1, heart2, heart3, heart4, heart5, heart6; public GameObject[] hearts; // Start is called before the first frame update void Start() { eff.SetActive(false); i = 0; StartCoroutine("Limittime"); StartCoroutine("Redeffect"); } // Update is called once per frame void Update() { } IEnumerator Limittime() { yield return new WaitForSeconds(4); /* heart1.SetActive(false); yield return new WaitForSeconds(4); heart2.SetActive(false); yield return new WaitForSeconds(4); heart3.SetActive(false); yield return new WaitForSeconds(4); heart4.SetActive(false); yield return new WaitForSeconds(4); heart5.SetActive(false); yield return new WaitForSeconds(4); heart6.SetActive(false); */ //入れ子ver if (i < 7) hearts[i].SetActive(false); i++; StartCoroutine("Limittime"); //入れ子ver } IEnumerator Redeffect() { yield return new WaitForSeconds(0.5f); eff.SetActive(true); yield return new WaitForSeconds(0.5f); eff.SetActive(false); StartCoroutine("Redeffect"); } } |
最後の部分で、 IEnumerator Redeffect(){} というコルーチンを定義しています。
ここでは画面が赤く点滅しているように表現しています。
そして入れ子にした事で、「for文」や「while文」を使った時のように、オブジェクトの配列に対して、アクティブの操作ができるようになっています。
さいごに
今回は、ゲーム制作に欠かせない時間の計測、監視を「非同期式制御」と「入れ子」を使って開発しました。
これで遅延を解消してみてはいかがでしょうか?
Unityでゲーム開発する時の参考になれば幸いです!
(株)ライトコードは、WEB・アプリ・ゲーム開発に強い、「好きを仕事にするエンジニア集団」です。
Unityでの開発依頼・お見積もりはこちらまでお願いします。
また、Unityを扱えるエンジニアを積極採用中です!詳しくはこちらをご覧ください。
※現在、多数のお問合せを頂いており、返信に、多少お時間を頂く場合がございます。
こちらの記事もオススメ!
ライトコードよりお知らせ






一緒に働いてくれる仲間を募集しております!
ライトコードでは、仲間を募集しております!
当社のモットーは「好きなことを仕事にするエンジニア集団」「エンジニアによるエンジニアのための会社」。エンジニアであるあなたの「やってみたいこと」を全力で応援する会社です。
また、ライトコードは現在、急成長中!だからこそ、あなたにお任せしたいやりがいのあるお仕事は沢山あります。「コアメンバー」として活躍してくれる、あなたからのご応募をお待ちしております!
なお、ご応募の前に、「話しだけ聞いてみたい」「社内の雰囲気を知りたい」という方はこちらをご覧ください。
ライトコードでは一緒に働いていただける方を募集しております!
採用情報はこちら書いた人はこんな人

IT技術2021.01.11React Hooks登場でコンポーネントはどう変わった?
IT技術2021.01.05【Unity】Rigidbodyの基本
IT技術2021.01.04【Unity】ARkit3を使ったARアプリを開発する方法を解説(AR foundation,iOS)
IT技術2020.12.29【機械学習】単純なアルゴリズムで迷惑メールを分類してみた