Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
184 views
in Technique[技术] by (71.8m points)

c# - Unity3D: How to do object pooling without a spawner singleton

Usually, if you use object pooling, you make a singleton like in this video. After seeing this video, I discovered how messy singleton can be. Is there any other way to do object pooling without using singletons? I wanna instead use Events.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You would need to hold the pool in a class which is not a singleton, and handle your gameobject pool according to your events. Regarding to call them with events, "I want to use events" is not a very concrete question. You need to set your events to listen (method subscribe) and to call them in the code wherever they're supposed to occur, this is invoke the method. I suggest that if you are not clear about this, try to use the unity events (OnTriggerEnter, if(Input.GetMouseButtonDown(0)) in the Update etc) until you dig in the topic enough to understand them and make ones of you own with c# events or UnityEvents when needed.

Find two template scripts, a pool and and event handler to handle your objects in the scene. You can check those out in an empty scene with your respective two gameObject to attach, and the object you want in the pool, pressing 'space' and 'A' to create from pool and return to pool respectively.

Pool manager:

using System.Collections.Generic;
using UnityEngine;

public class PoolManager : MonoBehaviour
{
    private Queue<GameObject> objPool;
    private Queue<GameObject> activeObj;
    private int poolSize = 10;
    public GameObject objPrefab;

    void Start()
    {
        //queues init
        objPool = new Queue<GameObject>();  
        activeObj = new Queue<GameObject>();
        //pool init
        for (int i = 0; i < poolSize; i++) 
        {
            GameObject newObj = Instantiate(objPrefab);
            objPool.Enqueue(newObj);   
            newObj.SetActive(false);    
        }
    }

    public GameObject GetRandomActiveGO() {
        GameObject lastActive = default;
        if (activeObj.Count > 0)
            lastActive = activeObj.Dequeue();
        else {
            Debug.LogError("Active object queue is empty");
        }
        return lastActive;
    }

    //get from pool
    public GameObject GetObjFromPool(Vector3 newPosition, Quaternion newRotation)
    {
        GameObject newObject = objPool.Dequeue();
        newObject.SetActive(true);
        newObject.transform.SetPositionAndRotation(newPosition, newRotation);

        //keep actives to be retrieved
        activeObj.Enqueue(newObject);
        return newObject;
    }

    //return to pool
    public void ReturnObjToPool(GameObject go)
    {
        go.SetActive(false);
        objPool.Enqueue(go);
    }
}

Event handler:

using UnityEngine;

public class EventHandler : MonoBehaviour
{
    public delegate GameObject OnSpacePressed(Vector3 newPosition, Quaternion newRotation);
    public OnSpacePressed onSpacePressed;

    public delegate void OnAKeyPressed(GameObject go);
    public OnAKeyPressed onAKeyPressed;

    public PoolManager poolManager;

    void Start()
    {
        onSpacePressed = poolManager.GetObjFromPool;
        onAKeyPressed = poolManager.ReturnObjToPool;
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            onSpacePressed?.Invoke(new Vector3(0, 0, 0), Quaternion.identity);
        }

        //here I get a random active, however this would be called in the specific objects remove circumstances, 
        //so you should have a reference to that specific gameobje when rerunrning it to the pool.
        if (Input.GetKeyDown(KeyCode.A))
        { 
            GameObject go = poolManager.GetRandomActiveGO();
            onAKeyPressed?.Invoke(go);
        }
    }
}

Edit: Singleton pattern

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    protected static T _instance;
    public static T instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = GameObject.FindObjectOfType<T>();
                if (_instance == null)
                {
                    _instance = new GameObject(typeof(T).Name).AddComponent<T>();
                }

            }
            return _instance;
        }
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...