質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.54%

Genericクラスのインスタンスのstatic化

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 732

Fujiyama

score 19

ObjectPoolを汎用的に扱えるようにGenericで記述しました。それを用いて、弾の発射、管理をするクラスを作成しました。現状ですと、start関数でシーン再読み込み時にまた別のインスタンスを生成してしまいますがここで生成したインスタンスを別のシーンに行ったとき(再読み込みも)にも使用したいと考えております。
staticを使えばシーンをまたいでも保持できると知り、色々試して見たもののうまくいきません。
下記のスクリプトですとエラーが出てしまいます。どうすれば、作成したインスタンスをシーンをまたいでも保持し、オブジェクトを再利用していけるようになるでしょうか?staticの使い方の理解がいまいちなのでご教授いただけると助かります。

MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
ObjectPool`1[Enemy].GetObject () (at Assets/Scripts/ObjectPool.cs:36)
PoolEnemy.Update () (at Assets/Scripts/PoolEnemy.cs:25)

if (!_objectList[i].activeInHierarchy)ここのことを指しております

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Boo.Lang.Environments;
using UnityEngine;

public class ObjectPool<T> where T : MonoBehaviour
{

    private List<GameObject> _objectList;
    private GameObject _objectInstance;
    private PrimitiveType _type;
    public int _objectLimit;
    public static ObjectPool<T> _instance;
     
    //弾を非アクティブに生成する
    public ObjectPool(int objectAmount,PrimitiveType type)
    {
        _type = type;
        if(_objectList==null) _objectList = new List<GameObject>();
        for (int i = 0; i < objectAmount; i++)
        {
            _objectInstance = GameObject.CreatePrimitive(_type);
            _objectInstance.SetActive(false);
            _objectInstance.name = typeof(T).Name;
            _objectInstance.tag = typeof(T).Name;
            _objectInstance.AddComponent<T>();
            _objectList.Add(_objectInstance);
        }
    }
  //弾をアクティブにして、足りなくなったら生成する
    public GameObject GetObject()
    {
        for (int i = 0; i < _objectList.Count; i++)
        {
            if (!_objectList[i].activeInHierarchy)
            {
                _objectList[i].SetActive(true);
                Debug.Log(_objectList[i].GetInstanceID());
                return _objectList[i];
            }

            if (_objectList.Count < _objectLimit)
            {
                GameObject _newObjectInstance = GameObject.CreatePrimitive(_type);
                _newObjectInstance.name = typeof(T).Name;
                _newObjectInstance.tag = typeof(T).Name;
                _newObjectInstance.AddComponent<T>();
                _objectList.Add(_newObjectInstance);
                return _newObjectInstance;
            }
        }

        return null;
    }


}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ShootBullet : MonoBehaviour
{

    private ObjectPool<Bullet> ObjectPool;

    // ObjectPoolのBullet型インスタンスの生成
    void Start () 
    {
        if (ObjectPool<Bullet>._instance == null)
        {
            ObjectPool = new ObjectPool<Bullet>(10, PrimitiveType.Sphere);
            ObjectPool<Bullet>._instance = this.ObjectPool;
            ObjectPool<Bullet>._instance._objectLimit = 20;
        }

    }

    // 弾を発射する
    void Update () {

        if (Input.GetMouseButtonDown(0))
        {
            Ray rayOrigin = Camera.main.ScreenPointToRay(Input.mousePosition);
            Vector3 direction = rayOrigin.direction;
            GameObject bullet =ObjectPool<Bullet>._instance.GetObject();
            bullet.GetComponent<Rigidbody>().velocity = direction * 20;
        }
    }


}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

static変数はシーンが切り替わっても維持されます。
ですが維持されるのは「インスタンス(そのクラスまたは変数)」であって、「その参照先」は別の話です。

例えば今、_objectListの中に幾つかのGameObjectが保持されているとします。
この時、GameObjectそのものがコピーされて入っているのではなく、対象のGameObjectへの参照が入っています。
「_objectListの0番はGameObjectAを指してるよ」「_objectListの1番はGameObjectBを指してるよ」といった具合です。
(これはstaticでもそうでなくても一緒)

シーン遷移時、staticなので_instanceは生き残り、その内部にある変数_objectListもキープされます。
ですがシーン遷移時にGameObjectは消える(Destroyされる)為、
「_objectListの0番はGameObjectAを指してるよ」という情報は残っていても、
「そのGameObjectA自体が存在していない」という状態になります。
なのでエラー文の通り「削除済みのGameObjectにアクセスしている」というエラーが発生します。

解決方法としては、シーン遷移時に参照先のGameObjectが消えなければいいので、
_objectInstanceを作成する部分に
DontDestroyOnLoad(_objectInstance);を追加すれば解決するかと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/23 14:42

    解決できました、ありがとうございます!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.54%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる