Unity-初心者のための概念的なアイデアとヒントigrodeva。 強力な2Dプロジェクトの最適化

このシリーズの最初の記事へのリンク。



クイックエントリー



今回はどのトピックを選ぶべきかを長い間考えていたので、ゲームの最適化に役立ついくつかの機能について説明することにしました。 ほとんどの場合、最初のゲームはスマートフォンやタブレット向けのゲームであることが判明するため、これは初心者には特に当てはまります。 そして、携帯電話では、コアの数が6〜8であっても、ゲームはリソース消費の点でまだ非常に不均衡です。 この記事で説明するコードとそのアイデアは、以前の出版物で引用した2行のコードよりも理解するのが少し難しいです。 正しくはしませんでした-コードは理解しやすいですが、この理解に入るためのしきい値は簡単なものよりもわずかに高くなります(もちろん初心者向け)、約5分間座っている必要があります。



アイデアの紹介



プレハブからUnityでオブジェクトをどのように作成しますか? インスタンス化するだけで、他には何もありません-別の関数は存在しません。



Instantiate()が何であるか覚えていない、またはまだ知らない人にとっては、ちょっとした助けが*インスタンス引数*です。 そのため、レベル(オブジェクト)を作成し、レベル全体で作成、場合によっては削除、再作成などを行います。 それは最適化に当たり、重要です-なぜですか それはすべてのUnityフォーラムに書かれており、時にはドキュメントにも表示されるため、ドキュメントに従う必要があるためです。 Instantiateはどのようにプロのパフォーマンスに影響しますか?



そのようなコードの例を次に示しますInstantiate(bullet, transform.position, tranform.rotation);







何が起こっているの? bullet変数に入れたプレハブが取得され、空きメモリがデバイスの腸で検索され、メモリが元のプレハブのサイズに割り当てられ、プレハブのコンポーネントの裸のコピーがそこに書き込まれ、元のプレハブのコンポーネントのすべてのパラメーターが新しいクローンにコピーされ、戻ります与えられた位置と角度でシーンに。



おそらく長い時間です。 ランナー(ゲーム内の5メートルごとにすべてのオブジェクトが繰り返される)または単なるシューターを実行していることを想像してください。少なくとも1秒ごとに上記の指示が発生すると、災害が発生します。 どうする? プール施設を使用します。



PS:オフィスでビデオがあります。 オブジェクトプーリングの概要とその方法に関するUnityサイト。 あなたが英語を話しているなら、それを見ることができます。 しかし、私は同じ考え方をしますが、このプーリングのより透過的な実装を使用します(ただし、コード行の観点からはより容量が大きくなります)。



行こう!



前回同様、現在のプロジェクトですべてをデモンストレーションします。 率直に言って、最初はオブジェクトプーリングをしませんでしたが、ゲームプレイ中にオブジェクトを作成しました。 そして、はい、ある時点で、多数の宇宙船が画面に現れて、それらがすべて撃ち始めたとき、FPSジャンプが現れ始めました、そして、これは非常に迷惑です。 やり直さなければなりませんでした。



この実装は、Unityからよりも面倒になることを繰り返します(同じクラスのインスタンスを使用して、別のオブジェクトに必要なオブジェクトのプール(箇条書きなど)を作成します。逆に、別のオブジェクトを作成しましたいわば、オブジェクトをプルするためのスクリプトマネージャーです。



つまり、私のUnityエディターでは、次のようになります(アイデアを完全に理解できるように)。







私はすべてを棚にきちんと保管するのが好きなので、2つの別々のマネージャー(弾丸用とさまざまな効果用)も持っています。



最初にアクションプランを説明し、次にコードを確認します。



1)プールオブジェクトを操作するスクリプトで、リスト(もちろんオブジェクト)を作成します。

2)ゲームの開始時に、プールに必要な数のオブジェクトをすぐにループで作成します。 そして、オブジェクトのインスタンスを1つ作成した後の各反復のループで、それをオフにして、前に作成したリストに追加します。

3)シート内のオブジェクトをアクティブにするオブジェクトのスクリプト(たとえば、ボートを制御するスクリプト)に移動します。 プールマネージャーであるオブジェクトへのリンクを作成します(または直接アクセスするためにプールを持つクラスを静的にします)。 そして、適切なタイミング(たとえば、射撃)で、コルーチン(通常は射撃にコルーチンが使用されます)で、必要なパラメーターを使用してプールのオブジェクトをアクティブ化する関数を呼び出します。 それだけです



同じことですが、実際には。 プールマネージャーコードが表示されます(1つのRedMissileオブジェクトのみ)。



 using UnityEngine; using System.Collections; using System.Collections.Generic; public class BulletsContainer : MonoBehaviour { List<GameObject> missileRed=new List<GameObject>(); //   RedMissile      public GameObject RedMissile; //  missileCount          public int misisleCount; void Awake() { //   ,          for(int i=0;i<missleCount;b++) { GameObject temp=(GameObject)Instantiate(RedMissile); temp.SetActive(false); missileRed.Add(temp); } } public void LaunchEnemyRedMissile(GameObject Caller) { if (missileRed != null) { for (int i=0; i<missileCount; i++) { //  -       //  ,       ,  //      if (!misisleRed [i].activeInHierarchy) { //    -  " missileRed [i].SetActive (true); " -   //            , //   ,       .   //     ,   ,      //      missileRed [i].SetActive (true); missileRed [i].transform.eulerAngles =Caller.transform.eulerAngles; missileRed [i].transform.position = Caller.transform.position; missileRed [i].GetComponent<DisableObject> ().StartCoroutine ("AblePause"); break; //     ,        }}}}}
      
      





次に、余分な行について説明します。



1) " missileRed [i] .transform.eulerAngles = Caller.transform.eulerAngles; "



-ご覧のとおり、関数の引数でCallerオブジェクトを受け入れます。誰もが、これがこの関数の呼び出し元のオブジェクトであると推測できると思います。 この次の行「 missileRed [i] .transform.position = Caller.transform.position; 」で行われているように、ほとんどの場合、これを呼び出しオブジェクトの位置でプールからオブジェクトをアクティブにするために行う必要があります。



2) " missileRed [i] .GetComponent().StartCoroutine(" AblePause "); "



-あなたも頻繁にやらなければなりません。 実際には、プールからオブジェクトをアクティブ化するたびに、しばらくしてから非アクティブ化する必要があります(たとえば、弾丸がプレイヤーの船に衝突したときなど、多くの非アクティブ化条件を設定できます。 .SetActive(false); ")。 したがって、プール内のすべてのオブジェクトに、一定の時間後にそれを無効にするスクリプトがあります。 繰り返しますが、プールオブジェクトを非アクティブ化することを忘れないでください。そうしないと、ある時点ですべてのオブジェクトがアクティブになり、アクティブ化サイクルが実行されなくなります。



次に、ボート内のコード(またはプールアクティベーション関数を呼び出すオブジェクト)は次のようになります。



 //....-  ..... //    ,    ,     //    : EnemiesContainer = GameObject.FindGameObjectWithTag ("ShipsGenerator"); BulletsSystem = EnemiesContainer.GetComponent<BulletsContainer> (); //....-  ..... IEnumerator StartAttack() { float randomTime = Random.Range (cooldownMin, cooldownMax ); yield return new WaitForSeconds (randomTime); //         ,    BulletsSystem.LaunchEnemyRedMissile(this.gameObject); } //....-  .....
      
      





おわりに



結果の例は次のとおりです-ステージ上の多数のオブジェクト、シーン全体のほぼ80%(船を除くすべて)がオブジェクトのプーリングによって作成され、わずかに長いレベルのロードを取得しますが、ゲームプレイ中にストッパーはありません。







PS:このテクニックは、繰り返しオブジェクトがあまりないゆったりとしたゲームの場合は使用する必要はありませんが、ランナーや元気いっぱいのシューティングゲームを作成する場合は、このテクニックを絶対に正確に使用する必要があります。 一般的に、すべては、いつものように-すべてが適度に良いです。



PPS:ご清聴ありがとうございました! 質問がありますか? コメントを書いてください-私は確かに答えます。



All Articles