【问题标题】:Move/Shift Objects in array up then move the first element to the last index [closed]向上移动/移动数组中的对象,然后将第一个元素移动到最后一个索引[关闭]
【发布时间】:2016-09-27 17:31:47
【问题描述】:

我正在 Unity3D 中构建一个游戏,我试图通过启用和禁用它们而不是实例化和销毁它们来重用游戏对象。

我在一个 GameObject 数组中有 10 个弹簧,每次我使用弹簧时,我都想从数组中的第一个元素中取出它,将该数组的所有剩余元素向上移动,然后将第一个对象移动到最后一个数组中的索引。

【问题讨论】:

  • 为什么不使用添加了禁用元素的队列,并且在需要时,您可以从队列中取出来获取先前禁用的实例,该实例只需要重新启用即可。为什么是数组?
  • @ray - 不确定,只是认为它可能有一个操作来完成我想要做的事情!以前从未使用过队列。
  • @LooMeenin:您应该检查文档以查看某个类是否提供了您正在寻找的操作,然后再尝试编写代码以发现情况并非如此。如果您以前从未使用过队列(这是一种基本数据结构),那么您可能需要在深入了解游戏编程之前或在学习游戏编程时更好地了解一些基础知识。

标签: c# arrays list unity3d


【解决方案1】:

这称为对象池。您不需要从第一个或最后一个删除数组来执行此操作。在 Unity 中有多种归档方式。

方法一(推荐):

即使这样有效,移动数组中的对象也是不必要且低效的。你可以有一个移动的索引。它从0 开始,每次您请求一个对象时,都会将其加一。如果索引等于Array.Length - 1,则将索引重置回0。

public class ArrayObjectPooling
{
    int amount = 10;
    GameObject[] objArray;
    int currentIndex = 0;

    public ArrayObjectPooling(GameObject objPrefab, string name, int count)
    {
        amount = count;
        objArray = new GameObject[amount];

        for (int i = 0; i < objArray.Length; i++)
        {
            objArray[i] = UnityEngine.Object.Instantiate(objPrefab, Vector3.zero, Quaternion.identity);
            objArray[i].SetActive(false);
            objArray[i].name = name + " #" + i;
        }
    }

    //Returns available GameObject
    public GameObject getAvailabeObject()
    {
        //Get the first GameObject
        GameObject firstObject = objArray[currentIndex];

        //Move the pointer down by 1
        shiftDown();

        return firstObject;
    }

    //Returns How much GameObject in the Array
    public int getAmount()
    {
        return amount;
    }

    //Moves the current currentIndex GameObject Down by 1
    private void shiftDown()
    {
        if (currentIndex < objArray.Length - 1)
        {
            currentIndex++;
        }
        else
        {
            //Reached the end. Reset to 0
            currentIndex = 0;
        }
    }
}

用法:

public GameObject prefab;

void Start()
{
    ArrayObjectPooling arrayPool = new ArrayObjectPooling(prefab, "Springs", 10);
    GameObject myObj = arrayPool.getAvailabeObject();
}

方法二:

如果池 小,

List 就足够了。请take 看看 Unity 的 Object Pooling 官方教程实现了这一点。此处无需贴代码。

您只需禁用 List 中的 GameObject 即可回收它。下次你需要一个新的时,循环List 并返回List 中第一个禁用的游戏对象。如果已启用,则表示它仍在使用中。

如果在List 中没有找到禁用的游戏对象,那么您可以Instantiate 一个新对象,将其添加到列表中然后返回。这是最简单的方法。只需观看 Unity 教程即可了解更多信息。


方法三:

使用队列或堆栈。您可以对池中的对象进行排队和入队或推送/弹出。如果您对此进行简单的研究搜索,则有很多实现。


方法四:

这只是因为这是您最初的问题,即如何在数组中向上移动对象,然后将第一个值放在数组的最后一个索引中。你不应该使用它。这里只是为了表明它可以做到。

public class ArrayObjectPooling
{
    int amount = 10;
    public GameObject[] objArray;

    public ArrayObjectPooling(GameObject objPrefab, string name, int count)
    {
        amount = count;
        objArray = new GameObject[amount];

        for (int i = 0; i < objArray.Length; i++)
        {
            objArray[i] = UnityEngine.Object.Instantiate(objPrefab, Vector3.zero, Quaternion.identity);
            objArray[i].SetActive(false);
            objArray[i].name = name + " #" + i;
        }
    }

    //Returns available GameObject
    public GameObject getAvailabeObject()
    {
        //Get the first GameObject
        GameObject firstObject = objArray[0];

        //Move everything Up by one
        shiftUp();

        return firstObject;
    }

    //Returns How much GameObject in the Array
    public int getAmount()
    {
        return amount;
    }

    //Moves the GameObject Up by 1 and moves the first one to the last one
    private void shiftUp()
    {
        //Get first GameObject
        GameObject firstObject = objArray[0];

        //Shift the GameObjects Up by 1
        Array.Copy(objArray, 1, objArray, 0, objArray.Length - 1);

        //(First one is left out)Now Put first GameObject to the Last one
        objArray[objArray.Length - 1] = firstObject;
    }
}

用法:

public GameObject prefab;

void Start()
{
    ArrayObjectPooling arrayPool = new ArrayObjectPooling(prefab, "Springs", 3);
    GameObject myObj = arrayPool.getAvailabeObject();
}

【讨论】:

  • 是的,想过,但不想检查游戏对象是否已启用。认为在某种类型的数组或列表中可能存在一个操作,它只是将 GameObject 抛出到数组/列表的末尾。这样我每次都可以使用数组中的第一个 GameObject 而无需检查
  • 我以前看过那个教程,过去我也使用过对象池,但我认为对于这种情况,我更愿意使用具有我描述的操作的某种数组或列表。如果没有这样的操作,那么我会想办法。
  • @LooMeenin 我正在尝试通过启用和禁用它们而不是实例化和销毁它们来重用游戏对象现在你说你不想检查它们是否被启用/禁用?为什么还要首先启用/禁用它们?你想用数组,如果你需要10个以上的弹簧怎么办?他们在比赛期间能保证永远是 10 岁吗?
  • 他们在游戏中保证永远是 10。我费心启用和禁用它们,因为在不使用时保持启用它们会产生性能税。
  • 是的,我可以在使用之前检查游戏对象是否已启用,但在游戏过程中大多数时候启用的弹簧多于禁用的,所以我不想循环几个只是为了找到一个禁用的如果我可以像我之前所说的那样每次都使用数组中的第一个。
猜你喜欢
  • 1970-01-01
  • 2019-11-08
  • 1970-01-01
  • 1970-01-01
  • 2021-12-15
  • 2017-12-14
  • 1970-01-01
  • 1970-01-01
  • 2020-07-15
相关资源
最近更新 更多