[RS] Timeline踩坑(2):The object ha

2022-07-28  本文已影响0人  _Walker__

记录环境

问题描述

  首先说明下,这个报错不是Unity直接抛出的,它就是我们写的轨道代码里,访问了一个已经被Destroy的对象。但是,导致这个报错出现,不是因为我们用法不合理!!!
  我们项目在切换情景的时候,会将当前情景的资源“全部卸载”,其中就包含TML及其控制的角色。
  我们在主城切换到副本的时候,爆出来这个MissingReferenceException的问题。检查后发现项目中资源释放的逻辑没有问题,轨道里的代码也符合制作规范。

统一资源释放流程(部分):
1.先停止所有正在播放的TML
2.释放/销毁资源,这里包含TML、角色等(这一步的顺序不重要)

轨道实现的规范(部分):
【轨道还原】在离开Clip、退出或销毁Track等时机时,要尽量还原被控角色的状态

  轨道还原是因为我们TML主要用在战斗中做技能表演,每个技能释放完毕后,需要角色还原到自己的出场站位,所以大部分轨道都需要做还原这个处理。
  基于TML的设定,我们在做资源释放时,就要保证上面的顺序。因为TML结束的时候,仍然会访问角色的对象,故TML需要先停止。

原因说明

  经过进一步打Log测试,我发现TML的停止跟Playable资源的停止并不是同步进行的。

测试得到一个结论:

PlayableDirector.Stop()与PlayerBehaviour.OnPlayableDestroy()是在同一帧执行,但不是同步执行,OnPlayableDestroy会晚一些。

测试的Log流程(下面这些全部在同一个Update帧输出):

  1. PlayableDirector.Stop()【主动停止TML】
  2. TimelineCtrl.OnDestroy()【停止TML后,销毁角色跟TML】
  3. Update() 开始【停止TML时,做了个标记让某个脚本的Update在第一行输出Log】
  4. Update() 结束【同上,在最后一行输出Log】
  5. PlayerBehaviour.OnPlayableDestroy()【Unity内部在UpdateDirectorUpdateRegistrator::Forward调过来】
  6. Frame End【停止TML时,开了个协程在WaitForEndOfFrame之后输出Log】
// OnPlayableDestroy的执行堆栈
MoleTimeline.MoleStateMixer:OnPlayableDestroy (UnityEngine.Playables.Playable) 
...
0x00007ff7ae5e01d4 (Unity) ScriptingInvocation::Invoke
0x00007ff7ae56f5c0 (Unity) PlayableMethods::InvokePlayableDestroy
0x00007ff7ae562112 (Unity) Playable::DeallocateResources
0x00007ff7ae568862 (Unity) PlayableGraph::DestroyPendingPlayables
0x00007ff7ae568387 (Unity) PlayableGraph::Destroy
0x00007ff7ae56c876 (Unity) DirectorManager::ProcessPlayStateChanges
0x00007ff7ae56a657 (Unity) `DirectorManager::InitializeClass'::`2'::UpdateDirectorUpdateRegistrator::Forward
0x00007ff7ae2a437c (Unity) ExecutePlayerLoop
0x00007ff7ae2a4453 (Unity) ExecutePlayerLoop
0x00007ff7ae2aa099 (Unity) PlayerLoop

推测: Unity内部维护了一个Playable的列表,并在Update里每帧去做清理,PlayableDirector.Stop只做了一个可销毁的标记。

解决方案

  暂时没找到比较好的解决方案,只是在每个Track的代码里,自己判断要用的资源是否合法。

上一篇下一篇

猜你喜欢

热点阅读