简体   繁体   English

Unity3D:如何在没有生成器的情况下进行 object 池化 singleton

[英]Unity3D: How to do object pooling without a spawner singleton

Usually, if you use object pooling, you make a singleton like in this video.通常,如果你使用 object 池,你会像视频中那样制作 singleton。 After seeing this video, I discovered how messy singleton can be.看完这个视频,我才发现singleton到底有多乱。 Is there any other way to do object pooling without using singletons?有没有其他方法可以在不使用单例的情况下进行 object 池化? I wanna instead use Events.我想改为使用事件。

You would need to hold the pool in a class which is not a singleton, and handle your gameobject pool according to your events.您需要将池保存在 class 而不是 singleton 中,并根据您的事件处理您的游戏对象池。 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.我建议,如果您不清楚这一点,请尝试使用统一事件( Update中的 OnTriggerEnter、 if(Input.GetMouseButtonDown(0))等),直到您深入了解主题以了解它们并制作自己的事件需要时使用 c# 事件或UnityEvents

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.您可以在一个空场景中检查它们,并附加两个要附加的游戏对象,以及池中您想要的 object,分别按“空格”和“A”从池中创建并返回到池中。

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编辑:Singleton 模式

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;
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM