Unity3D:如何在没有 spawner 单例的情况下进行对象池化 [英] Unity3D: How to do object pooling without a spawner singleton

查看:12
本文介绍了Unity3D:如何在没有 spawner 单例的情况下进行对象池化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通常,如果你使用对象池,你会像这个视频.看完这个视频后,我发现单身人士是多么的凌乱.有没有其他方法可以在不使用单例的情况下进行对象池化?我想改用事件.

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.

推荐答案

您需要将池保存在一个不是单例的类中,并根据您的事件处理您的游戏对象池.关于用事件调用它们,我想使用事件";不是一个非常具体的问题.您需要将事件设置为侦听(方法订阅)并在代码中应该发生的任何地方调用它们,这就是调用方法.我建议,如果您对此不清楚,请尝试使用统一事件(OnTriggerEnter、if(Input.GetMouseButtonDown(0)) in the Update etc),直到您深入挖掘主题以了解它们,并在需要时使用 c# 事件或 UnityEvents 使您拥有自己的主题.

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.

找到两个模板脚本、一个池和一个事件处理程序来处理场景中的对象.你可以在一个空的场景中用你各自的两个游戏对象来检查它们,以及你想要在池中的对象,按空格"和A"分别从池中创建和返回池.

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.

池经理:

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

事件处理程序:

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

单例模式

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

这篇关于Unity3D:如何在没有 spawner 单例的情况下进行对象池化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆