【问题标题】:How can I position random objects on x,y,z using object pool?如何使用对象池在 x、y、z 上放置随机对象?
【发布时间】:2019-02-26 21:15:13
【问题描述】:

我有两个脚本,每个脚本都附加到另一个空游戏对象:

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

public class ObjectPooler : MonoBehaviour
{
    [System.Serializable]
    public class Pool
    {
        public string tag;
        public GameObject prefab;
        public int size;
    }

    #region Singleton

    public static ObjectPooler Instance;

    private void Awake()
    {
        Instance = this;
    }

    #endregion

    public List<Pool> pools;
    public Dictionary<string, Queue<GameObject>> poolDictionary;

    // Start is called before the first frame update
    void Start()
    {
        poolDictionary = new Dictionary<string, Queue<GameObject>>();

        foreach(Pool pool in pools)
        {
            Queue<GameObject> objectPool = new Queue<GameObject>();

            for(int i = 0; i < pool.size; i++)
            {
                GameObject obj = Instantiate(pool.prefab);
                obj.SetActive(false);
                objectPool.Enqueue(obj);
            }

            poolDictionary.Add(pool.tag, objectPool);
        }
    }

    public GameObject SpawnFromPool(string tag, Vector3 position, Quaternion rotation)
    {
        if(!poolDictionary.ContainsKey(tag))
        {
            Debug.LogWarning("Pool with tag " + tag + " doesn't exist.");
            return null;
        }

        GameObject objectToSpawn = poolDictionary[tag].Dequeue();

        objectToSpawn.SetActive(true);
        objectToSpawn.transform.position = position;
        objectToSpawn.transform.rotation = rotation;

        IPooledObject pooledObj = objectToSpawn.GetComponent<IPooledObject>();

        if(pooledObj != null)
        {
            pooledObj.OnObjectSpawn();
        }

        poolDictionary[tag].Enqueue(objectToSpawn);

        return objectToSpawn;
    }
}

第二个,这里我在 FixedUpdate 里面添加了随机部分:

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

public class CubeSpawner : MonoBehaviour
{
    ObjectPooler objectPooler;

    // Start is called before the first frame update
    void Start()
    {
        objectPooler = ObjectPooler.Instance;
    }

    private void FixedUpdate()
    {
        var randp = new Vector3(Random.Range(0, 300), Random.Range(0, 300), Random.Range(0, 300));
        objectPooler.SpawnFromPool("Cube", randp, Quaternion.identity);
    }
}

到目前为止,它做了我想要的,但是我是否在正确的脚本和位置中添加了随机部分?

我怎样才能做到这一点,而不是生成不间断的随机对象,它只会在我更改大小变量的范围滑块时生成它们?

例如 [范围(1,150])

当我更改值时,它会添加/删除 FixedUpdate 中的对象吗? (应该是 Update 它是 FixedUpdate,因为之前我使用的是刚体,但现在不是)。

这个想法是要么更改大小,要么我将大小设置为 1000,然后使用范围滑块更改使用对象的数量,例如 445、500 或 1000。

每次我更改大小时,它都会随机将对象放在其他随机位置。但是像现在在 FixedUpdate 中的一次而不是所有时间。

每次改变大小都会随机改变对象的位置。 因此,如果我将大小更改为 10,则随机更改 10 个对象的位置并仅使用这 10 个对象。如果我将大小更改为 700,然后随机重新定位 700 个对象并使用 700。(不确定说使用或销毁是否正确)。

更新:

这是我在第一个脚本中尝试的,我添加了 oldSize 变量和 Range:

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

public class ObjectPooler : MonoBehaviour
{
    [System.Serializable]
    public class Pool
    {
        public string tag;
        public GameObject prefab;
        [Range(1, 150)]
        public int size;
        public int sizeOld;
    }

    #region Singleton

    public static ObjectPooler Instance;

    private void Awake()
    {
        Instance = this;
    }

    #endregion

    public List<Pool> pools;
    public Dictionary<string, Queue<GameObject>> poolDictionary;

    // Start is called before the first frame update
    void Start()
    { 
        poolDictionary = new Dictionary<string, Queue<GameObject>>();

        foreach(Pool pool in pools)
        {
            Queue<GameObject> objectPool = new Queue<GameObject>();

            for(int i = 0; i < pool.size; i++)
            {
                GameObject obj = Instantiate(pool.prefab);
                obj.SetActive(false);
                objectPool.Enqueue(obj);
            }

            poolDictionary.Add(pool.tag, objectPool);
        }
    }

    private void Update()
    {

    }

    public GameObject SpawnFromPool(string tag, Vector3 position, Quaternion rotation)
    {
        if(!poolDictionary.ContainsKey(tag))
        {
            Debug.LogWarning("Pool with tag " + tag + " doesn't exist.");
            return null;
        }

        GameObject objectToSpawn = poolDictionary[tag].Dequeue();

        objectToSpawn.SetActive(true);
        objectToSpawn.transform.position = position;
        objectToSpawn.transform.rotation = rotation;

        IPooledObject pooledObj = objectToSpawn.GetComponent<IPooledObject>();

        if(pooledObj != null)
        {
            pooledObj.OnObjectSpawn();
        }

        poolDictionary[tag].Enqueue(objectToSpawn);

        return objectToSpawn;
    }
}

在 Start 的第二个脚本中,我使用了整个对象,例如当 Range 值为 27 时开始游戏,然后在更改值时更新 oldSize:

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

public class CubeSpawner : MonoBehaviour
{
    ObjectPooler objectPooler;

    // Start is called before the first frame update
    void Start()
    {
        objectPooler = ObjectPooler.Instance;

        foreach (ObjectPooler.Pool pool in objectPooler.pools)
        {
            var randp = new Vector3(Random.Range(0, 300), Random.Range(0, 300), Random.Range(0, 300));
            objectPooler.SpawnFromPool("Cube", /*transform.position*/ randp, Quaternion.identity);
        }
    }

    private void Update()
    {
        foreach (ObjectPooler.Pool pool in objectPooler.pools)
        {
            if (pool.size != pool.sizeOld)
            {
                int diff = pool.size - pool.sizeOld;
                pool.sizeOld = pool.size;

                // Spawn new diff number of objects if diff is positive
                var randp = new Vector3(Random.Range(0, 300), Random.Range(0, 300), Random.Range(0, 300));
                objectPooler.SpawnFromPool("Cube", /*transform.position*/ randp, Quaternion.identity);
            }
        }
        //var randp = new Vector3(Random.Range(0, 300), Random.Range(0, 300), Random.Range(0, 300));
        //objectPooler.SpawnFromPool("Cube", transform.position /*randp*/, Quaternion.identity);
    }
}

但实际上层次结构中的生成器从未改变,始终是 27。如果范围低于 27,它将使用更少的对象,但如果大于 27,层次结构中仍然只有 27 个生成器。

生成器的大小永远不会改变。然后当左右移动范围时,它会填满产卵者使用它们直到结束,就是这样,它永远不会改变它会全部使用它们,但只有 27 个。

例如,即使 Range 值为 150,层次结构中仍然有 27 个生成器,并且在游戏中它自己而不是 150。

【问题讨论】:

    标签: c# unity3d


    【解决方案1】:

    到目前为止,它做了我想要的,但是我是否在正确的脚本和位置中添加了随机部分?

    我不知道,如果你问我是1 + 1 = 2,我可以给你答案。

    我怎样才能让它生成不间断的随机对象,只有当我更改大小变量的范围滑块时才会生成它们?

    您需要另一个尺寸字段:

    public class Pool
    {
        public string tag;
        public GameObject prefab;
        [Range(1, 150)]
        public int size;
        private int sizeOld;
    }
    

    然后在FixedUpdate的Update中做一个简单的比较:

    void Update()
    {
        foreach(Pool pool in pools)
        {
            if(pool.size != pool.sizeOld)
            {
                int diff = pool.size - pool.sizeOld;
                pool.sizeOld = pool.size;
    
                // Spawn new diff number of objects if diff is positive
            }
        }
    }
    

    当我更改值时,它会在 FixedUpdate 中添加/删除对象?

    取决于你调用生成方法的位置。

    【讨论】:

    • FixedUpdate 的更新是什么意思?您的意思是在第二个脚本中 CubeSpawner 并在那里创建 Update 并将其放入 Update ?然后删除 FixedUpdate ?我尝试将它放在 CubeSpawner 脚本的 FixedUpdate 中,并引用第一个脚本,但效果不佳。
    • 如果我以 27 个对象开始游戏,那么更改对象的大小和 oldsize 的数量是相同的值。而在层次结构中仍然只有 27 个刷怪箱。同样在游戏中只有 27。无论我将其更改为 70 大小还是将其更改为 5。仍然有 27。第一次运行游戏时它不会使用整个 27,或者如果我从 150 开始它是仅使用第一个生成器。
    • 也许你能告诉我完整的代码应该是什么样子?也许我错过了什么?
    • 使用UpdateFixedUpdate 由你决定,我只是写一个例子。这里没有完整代码,自己写生成方法(在注释行的地方)。
    • size 和 oldsize 是相同的值 ...正如您所见,代码只有在它们不相等时才会更改 sizeOld
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-17
    • 1970-01-01
    • 2020-03-27
    相关资源
    最近更新 更多