【问题标题】:Unity Reusing Ui element in listUnity重用列表中的UI元素
【发布时间】:2016-06-11 07:28:29
【问题描述】:

我在我的项目中遇到了一个问题,我正在创建一个滚动列表视图来显示屏幕中列表中存在的所有元素。 我正在使用面板中的按钮来显示列表。 现在,当我调用 ShowList() 时,它会显示列表中的元素。

但是,如果我将一些对象添加到列表中并再次调用 ShowList(),那么它也会克隆先前的对象,因为存在实例化对象。

为了解决这个问题,我正在使用 Destroy() 删除克隆,但是当列表包含太多项目 (300~400) 时,删除它们会导致游戏延迟。如何为 ui 按钮创建对象池或只是停用它们。

 public class two : MonoBehaviour {

        public GameObject Button_Template;

        private List<GameName> gm = new List<GameName>();


        public void Exit()
        {
            var og = GameObject.FindGameObjectsWithTag("clone");
            for (int i = 0; i < og.Length; i++)
            {
                Destroy(og[i]);
            }
        }
        void Start()
        {   gm.Add(new GameName("1"));
            gm.Add(new GameName("2"));
            gm.Add(new GameName("3"));
            gm.Add(new GameName("4"));

            }


      public  void ShowList()
        {

            for (int i = 0 ; i < gm.Count; i++)
                {
                    GameObject go = Instantiate(Button_Template) as GameObject;
                    go.SetActive(true);
                    one TB = go.GetComponent<one>();
                    TB.SetName(gm[i].GName);
                    go.transform.SetParent(Button_Template.transform.parent);
                    go.tag = "clone";
                }



        }


    }

【问题讨论】:

  • 有没有可能,简单地说,您需要开始使用预制件?
  • 我尝试过使用预制件,但它仍然滞后,因为我正在实例化超过 500 个项目的按钮。当我使用 OnGui 时,它可以正常工作但我在某处读到的总是使用画布而不是 gui
  • 您应该使用 Programmer 提供的出色解决方案。没有理由你应该拥有“500”的任何东西。如果你这样做,你必须使用 pooling。这是您了解它的好机会。

标签: c# unity3d unityscript unity5


【解决方案1】:

List 可用于实现对象池。使用完游戏对象后,只需 disable 即可。如果您想再次使用它,请重新启用它。下面简单的 GameObject Pool 脚本重新实现了 InstantiateDestroy 函数。

public class BUTTONPOOL : MonoBehaviour
{

    GameObject buttonPrefab;
    List<GameObject> buttonPool;
    bool ready = false;

    public void createButtonPool(GameObject buttonPrefab, int amount = 400)
    {
        if (ready)
        {
            Debug.LogError("createButtonPool can only be called once");
            return;
        }

        this.buttonPrefab = buttonPrefab;

        //Create 400 Buttons
        buttonPool = new List<GameObject>();
        for (int i = 0; i < amount; i++)
        {
            buttonPool.Add(Instantiate(this.buttonPrefab) as GameObject);
        }
        ready = true;
    }

    //Creates/Enables single Button
    public GameObject Instantiate()
    {
        if (!ready)
        {
            showError();
            return null;
        }

        //Return any Button that is not active
        for (int i = 0; i < buttonPool.Count; i++)
        {
            if (!buttonPool[i].activeSelf)
            {
                return buttonPool[i];
            }
        }

        //Create new Button if there is none available in the pool. Add it to the list then return it
        GameObject tempButton = Instantiate(this.buttonPrefab) as GameObject;
        buttonPool.Add(tempButton);
        return tempButton;
    }

    //Destroys/Disables single Button
    public void Destroy(GameObject button)
    {
        if (!ready)
        {
            showError();
            return;
        }
        button.SetActive(false);
    }

    //Destroys/Disables all Buttons
    public void DestroyAll()
    {
        if (!ready)
        {
            showError();
            return;
        }
        for (int i = 0; i < buttonPool.Count; i++)
        {
            if (buttonPool[i].activeSelf)
            {
                buttonPool[i].SetActive(false);
            }
        }
    }

    private void showError()
    {
        Debug.LogError("createButtonPool must be called once before any other function can be called");
    }
}

用法:

public GameObject ButtonPrefab;
BUTTONPOOL bPool;

void test()
{
    if ((bPool = GetComponent<BUTTONPOOL>()) == null)
    {
        gameObject.AddComponent<BUTTONPOOL>();
        bPool = GetComponent<BUTTONPOOL>();
    }

    //Initiate with 300 Buttons
    bPool.createButtonPool(ButtonPrefab, 50);

    GameObject tempButton = bPool.Instantiate();

    //MUST SET BUTTON ACTIVE CALLING Instantiate()
    tempButton.SetActive(true);

    //You can do other things with the button
     one TB = tempButton.GetComponent<one>();

    //To destroy that single button
    bPool.Destroy(tempButton);

    //OR destroy that all button
    bPool.DestroyAll();
}

请注意,从BUTTONPOOL 脚本调用自定义Instantiate() 函数后,您必须将Button 设置为活动状态。

【讨论】:

  • 我认为对象池对我没有帮助,因为,我正在实例化按钮有时几乎 500 多个项目,所以它会滞后,但如果我使用 OnGui,那么它可以毫无滞后地工作但我在某处读到总是使用画布而不是 gui 我仍在考虑可能的解决方案
  • @paulp 2 天后回复了一篇没有意义的帖子。 我不认为对象池对我有帮助,因为我有时会实例化按钮将近 500 多个项目,所以它会滞后你知道什么是对象池吗?你知道为什么实例化滞后吗?随意坚持使用“有效”的 OnGUI。我已经尽了我的一份力来解决您的冻结问题,但不能强迫您使用它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-12
  • 2019-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多