【Unity】坑

记录在unity中遇到的各种坑

对象销毁

GameObject被销毁后,!= null任然可能为true。比如有一个PanelBattle的类,如果你在另外一个地方存储了该类,然后又销毁了这个对象。此时如果你再访问这个对象是不会报空的(因为PanelBattle != null),但是如果你访问其中的元素就会报空(因为PanelBattle.m_btnStartButton == null)。

解决方案:在判断GameObject是否为空的时候添加一个判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 以下只是举个例子,不要这样写。
// 正常情况下,不应该直接使用GetWindow来获取其他UI实例,UI与UI之间应该使用事件来通讯。
private PanelBattle _panelBattleCache;
private PanelBattle _panelBattle
{
get
{
if (_panelBattleCache == null || _panelBattleCache.gameObject == null)
{
_panelBattleCache = GameModule.UI.GetWindow<PanelBattle>();
}

return _panelBattleCache;
}
}

案例一:

前提:你需要在物体A的下方安放子物体B,A初始化时需要获取所有的子物体B,之后物体B的数量将不再改变

触发条件:在同一帧下先回收了物体B,然后又创建了物体B,然后又初始化了A

结果:物体A使用的GetComponentsInChildren会获取到两个物体B,并且第一个B会在下一帧被回收掉,导致后续的代码会报空

解决方法:不再直接销毁掉物体B,而是使用对象池,将其回收到对象池(也就是改变了其父级),这样物体A使用GetComponentsInChildren时就只会获取到一个B

案例二:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private PanelBattle _panelBattleCache;
private PanelBattle _panelBattle
{
get
{
// 这里 不仅需要判断PanelBattle == nukll,还需要判断.gameObject == null
// 因为如果PanelBattle被销毁过一次的话,_panelBattleCache一直是是被销毁但未被回收的gameObject
// 注:当PanelBattle直接继承MonoBehaviour可以不用做此操作,因为继承了MonoBehaviour的对象在判断==时会进行隐式检查
if (_panelBattleCache == null || _panelBattleCache.gameObject == null)
{
_panelBattleCache = GameModule.UI.GetWindow<PanelBattle>();
}

return _panelBattleCache;
}
}