以前使用Destroy删除游戏物体,删了就删了,也没有使用过DestroyImmediate来删除游戏物体

今天使用Destroy却碰到了一个坑,故顺便记录一下

在文章开始前,我们有必要区分一下使用Destroy和DestroyImmediate删除游戏物体有什么区别?

1   使用Destroy删除游戏物体,游戏物体并不会立即被删除,而是异步执行的,不会影响主线程的执行,说白了,就是它另外开一条道去执行了,这点很重要,接下来的例子就会有体现

2  使用DestroyImmediate删除游戏物体,游戏物体立即被删除,代码顺序执行,影响主线程的执行

首先先介绍一下问题的背景

我做的是一个习题系统,包括选择题、填空题和简答题,填空题的界面如下图:

为了方便描述,请允许我把

这一块东西叫做 ‘框’,如上面的叫  ‘框1’

使用AnswerPanel1为模板,生成填空题的  ‘空2’(‘框2’)、‘空3’('框3')、‘空4’('框4)等,为了程序方便操作,名称对应为AnswerPanel2、AnswerPanel3 、AnswerPanel4 等  。 因为需要填空的个数是不确定的,需要根据每道题的问题中需要填空的个数来动态生成  ‘框’

以点击  ‘上一题’的按钮为例进行说明,当用户点击该按钮时,保存用户输入的答案,并把这道题中的所有的  ‘框’(除了'框1')都进行删除,接着在这个界面加载上一道题的题目,并根据题目中空的个数来动态绘制 ‘框’的个数,最后,还需要把用户在这道题填了那些内容加载回来并显示回对应的 ‘框’。

总的业务逻辑描述如下图:

执行第一步时,使用Destroy删除 ‘框’时,发现一个很奇怪的问题,第三步动态绘制的 ‘框’的个数是正确的,但是到第四步时,显示回用户的答案时总是不正确(只有'框1'显示的答案正确,其它的‘框’需要显示的答案直接不显示)

出现这种情况的原因是: 使用Destroy删除时,是异步删除(它是另外开道执行删除),如本道题的 ‘框3’还没有删除,上一道题的 ‘框3’就已经绘制完毕,而且两个 ‘框3’是同名的,有两个同名的 ‘框3’,当执行到第四步时,通过GameObject.Find('框3名称')的方式找到 ‘框3’,这时找到的是本道题的  ‘框3’,并把用户对应的答案显示回找的的 ‘框3’,当本道题的 ‘框3’删除了,留下的是你所看到的上一道题的  ‘框3’(空的,本来该有的,却变成啥也没有)

解决办法,就行删除时,不让它另外开道进行删除,说白了,就是第一步就彻底删完,不删除就不执行第二步,这时DestroyImmediate就派上用场了,把使用Destroy的地方替换为DestroyImmediate

本以为一切都结束时,又踩了一个不该踩的坑。

我使用的方法是: 找到  ‘框’的父游戏物体,是上面第一张图 中的  AnswerPanel,然后删除AnswerPanel下的所有子物体(除了 '框1'),代码如下:

private RectTransform  _AnswerPanelTransform;

 _AnswerPanelTransform = GameObject.Find("AnswerPanel").GetComponent<RectTransform>();

        //每次绘制前,都把上一次绘制的删除
        for (int childIndex =0; childIndex< _AnswerPanelTransform.childCount; childIndex++)
        {
            if (_AnswerPanelTransform.GetChild(childIndex).gameObject.name != "AnswerPanel1")
            {
                GameObject.DestroyImmediate(_AnswerPanelTransform.GetChild(childIndex).gameObject);
            }
           
        }

不知你有没有发现问题所在,是真的能够全部删除(除了'框1')吗?答案是非也,AnswerPanel每删除一个子物体,它的childCount值就减少1,就好像是你要删除一个List中的一个元素一样,当List中有10个对象的时候,如果RemoveAt掉了第0个,那么后面的9个对象都会向前移动。

解决办法是:设置childIndex的初始值为:_AnswerPanelTransform.childCount-1,代码如下:

 private RectTransform  _AnswerPanelTransform;

 _AnswerPanelTransform = GameObject.Find("AnswerPanel").GetComponent<RectTransform>();

        //每次绘制前,都把上一次绘制的删除
        for (int childIndex = _AnswerPanelTransform.childCount-1; childIndex >=0; childIndex--)
        {
            if (_AnswerPanelTransform.GetChild(childIndex).gameObject.name != "AnswerPanel1")
            {
                GameObject.DestroyImmediate(_AnswerPanelTransform.GetChild(childIndex).gameObject);
            }
           
        }

 好了,本文到此结束,如果本文对你有帮助,资助2毛钱作为鼓励呗,穷逼一个,就当筹个网费吧

Logo

这里是一个专注于游戏开发的社区,我们致力于为广大游戏爱好者提供一个良好的学习和交流平台。我们的专区包含了各大流行引擎的技术博文,涵盖了从入门到进阶的各个阶段,无论你是初学者还是资深开发者,都能在这里找到适合自己的内容。除此之外,我们还会不定期举办游戏开发相关的活动,让大家更好地交流互动。加入我们,一起探索游戏开发的奥秘吧!

更多推荐