今作成中のシューティングゲームがInstantiateとDestroyを繰り返し、モバイル端末だと特に動きがカクカクになってきました。何かいい手はないかと思って調べているとオブジェクトプールという手段を知り、3日ほど挑戦していますが、うまくできなかったので質問させていただきます。
作成中のシューティングゲームは基本的にUnityの公式のチュートリアルを参考にしています。公式のオブジェクトプールのチュートリアルも試してみたんですが、結構変更している部分があり、公式のようにはなりませんでした。
タップして動かし連続して弾を撃つプレイヤーと、生成されると一定のスピードで動き、一定の間隔で弾を撃ってくるエネミーがあります。
エネミーには弾を撃つものと撃たないものがあり、撃つものはshotPositionを子要素として持ちます。エネミーは何種類かあり、撃つ弾の種類も、shotPositionの数や位置も変わってきます。
lang
1using UnityEngine; 2using System.Collections; 3 4public class Enemy : MonoBehaviour 5{ 6 7 Spaceship spaceship; 8 9 public int hp; 10 11 IEnumerator Start() 12 { 13 spaceship = GetComponent<Spaceship>(); 14 15 spaceship.Move(transform.up * -1); 16 17 if (spaceship.canShot == false) 18 { 19 yield break; 20 } 21 22 while (true) 23 { 24 for (int i = 0; i < transform.childCount; i++) 25 { 26 Transform shotPosition = transform.GetChild(i); 27 28 spaceship.Shot(shotPosition); 29 } 30 yield return new WaitForSeconds(spaceship.shotDelay); 31 } 32 33 } 34 void OnTriggerEnter2D(Collider2D c) 35 { 36 if (c.tag != "Bullet(Player)") return; 37 38 Transform playerBulletTransform = c.transform.parent; 39 40 Bullet bullet = playerBulletTransform.GetComponent<Bullet>(); 41 42 hp = hp - bullet.power; 43 44 Destroy(c.gameObject); 45 46 47 if (hp <= 0) 48 { 49 50 spaceship.Explosion(); 51 52 Destroy(gameObject); 53 } 54 } 55} 56
このエネミースクリプトから
lang
1using UnityEngine; 2using System.Collections; 3using System.Collections.Generic; 4 5[RequireComponent(typeof(Rigidbody2D))] 6public class Spaceship : MonoBehaviour { 7 8 public float speed; 9 10 public float shotDelay; 11 12 public GameObject bullet; 13 14 public bool canShot; 15 16 public GameObject explosion; 17 18 19 public void Shot(Transform origin) 20 { 21 Instantiate(bullet, origin.position, origin.rotation); 22 } 23 public void Move(Vector2 direction) 24 { 25 GetComponent<Rigidbody2D>().velocity = direction * speed; 26 } 27 public void Explosion() 28 { 29 Instantiate(explosion, transform.position, transform.rotation); 30 } 31 32} 33 34
スペースシップスクリプトのShot(transform origin)を呼び出してエネミーごとに自分の子要素であるshotPositionのtransformを渡して、その位置から弾を撃っています。
Shot文で呼び出されたbulletはバレットスクリプトを持っており、
lang
1using UnityEngine; 2using System.Collections; 3 4public class Bullet : MonoBehaviour 5{ 6 7 public int speed = 10; 8 9 public int power; 10 11 12 void Start() 13 { 14 GetComponent<Rigidbody2D>().velocity = transform.up.normalized * speed; 15 } 16}
バレットスクリプトでは、生成されると同時にまっすぐ進むだけです。
プレイヤーが撃った弾はエネミーにあたるとDestroyされます。
ステージの四方をDestroyAreaに囲まれており、敵に当たらなかったプレイヤーの弾やエネミーの弾はDestroyAreaに当たることで、破壊されるようになっています。
http://megumisoft.hatenablog.com/entry/2016/06/25/133033
調べたところ、こちらのサイトが一番わかりやすく、アレンジできそうでしたので試行錯誤しましたができませんでした。サイトの方にあるBulletGeneratorクラスにあることをこちらのSpaceshipに書けば実装できそうな気がしましたが、こちらでのエネミーごとに違うshotPositionから発射するということが障害になっているのか、うまくできませんでした。
情報等足りないところや、わかりにくいところ等あれば追記します。
ぜひ回答よろしくお願いします。
以下追記になります。
kaka1102さんの回答を参考にいろいろ変更してみました。
プレイヤーはエネミーの弾は管理していなく、プレイヤーとエネミーが共通して持っているスペースシップというスクリプトで弾の撃つ撃たないを管理しています。
なので、参考サイト、kaka1102さんが仮に作成したBulletGeneratorを組み合わせて、スペースシップに追加してみました。
lang
1using UnityEngine; 2using System.Collections; 3using System.Collections.Generic; 4 5[RequireComponent(typeof(Rigidbody2D))] 6public class Spaceship : MonoBehaviour { 7 8 List<Bullet> list_Bullets = new List<Bullet>(); 9 10 const int MAX_BULLETS = 20; 11 12 13 public float speed; 14 15 public float shotDelay; 16 17 public GameObject bullet; 18 19 public bool canShot; 20 21 public GameObject explosion; 22 23 void Start() 24 { 25 Bullet bulleta; 26 // 最初に一定数の弾を備蓄しておく 27 for (int i = 0; i < MAX_BULLETS; i++) 28 { 29 // 弾の生成 30 bulleta = Instantiate(bullet).GetComponent<Bullet>(); 31 32 bulleta.transform.parent = this.transform; 33 // 発射前は非アクティブにしておく 34 bulleta.gameObject.SetActive(false); 35 // Listに追加 36 list_Bullets.Add(bulleta); 37 } 38 } 39 40 41 public void Shot(Transform origin) 42 { 43 for (int i = 0; i < list_Bullets.Count; i++) 44 { 45 { 46 if (!list_Bullets[i].gameObject.activeSelf) 47 { 48 list_Bullets[i].transform.position = origin.position; 49 list_Bullets[i].transform.rotation = origin.rotation; 50 list_Bullets[i].gameObject.SetActive(true); 51 break; 52 } 53 } 54 55 56 57 //Instantiate(bullet, origin.position, origin.rotation); 58 } 59 } 60 public void Move(Vector2 direction) 61 { 62 GetComponent<Rigidbody2D>().velocity = direction * speed; 63 } 64 public void Explosion() 65 { 66 Instantiate(explosion, transform.position, transform.rotation); 67 } 68 69}
すると、最初の一発は弾を発射するんですが、次からはこのように止まってしまいました。
この状態では、エラーは出ませんが、画像にあるDestroyAreaという画面外のオブジェクトに当たりエネミーが破壊され、次のエネミーが出てきたところで
UnassignedReferenceException: The variable bullet of Spaceship has not been assigned.
You probably need to assign the bullet variable of the Spaceship script in the inspector.
UnityEngine.Object.Instantiate[GameObject] (UnityEngine.GameObject original) (at C:/buildslave/unity/build/Runtime/Export/UnityEngineObject.cs:189)
という同じエラーが3つ出てきます。
このエラーをダブルクリックした先はスペースシップスクリプトの
bulleta = Instantiate(bullet).GetComponent<Bullet>();
になります。
画像中でプレイヤーか弾が出ていませんが、プレイヤーの弾はDestroyAreaにあたると、非表示になった状態で、上へ永遠に飛んで行っていました。
DestroyAreaのスクリプトはこちらです。
lang
1using UnityEngine; 2using System.Collections; 3 4public class DestroyArea : MonoBehaviour { 5 6 void OnTriggerEnter2D(Collider2D c) 7 { 8 if (c.tag == "Bullet(Player)") 9 { 10 c.gameObject.SetActive(false); 11 } 12 else if (c.tag == "Bullet(Enemy)") { 13 c.gameObject.SetActive(false); 14 } 15 else 16 { 17 Destroy(c.gameObject); 18 } 19 } 20} 21
以上kaka1102さんの回答を参考に改良した点になります。
よろしくお願いします。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/12/15 18:38
2016/12/25 18:14
退会済みユーザー
2016/12/27 07:56
退会済みユーザー
2016/12/28 11:46
2017/01/11 15:07