fix(enemy): 修复退出 Play 时巡逻调试 Inspector 的 NRE 与 IMGUI 报错
退出 Play 有一个窗口:Application.isPlaying 仍为 true 但 PBWorld 已销毁,此时 Inspector
调 nav.CanReach → PBWorld.PathTo(instance=null) 抛 NRE;该异常在 IMGUI 布局组中途中断,
使 BeginHorizontal 组失衡 → 级联 ArgumentException("control N in a group with only N controls")。
修:
- 订阅 playModeStateChanged,ExitingPlayMode 置 _exitingPlay,CanReach 调用点加
!_exitingPlay && isPlaying 守卫,退出期不再查询已销毁的 PBWorld。
- 运行时区块的绘制判定只在 Layout 事件锁定、Repaint 复用,避免 isPlaying 在两趟 GUI
间翻转导致控件数不一致。
实测:选中敌人连续两次进/退 Play,Console 无 NRE/ArgumentException。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,8 +30,29 @@ namespace BaseGames.Editor
|
||||
private bool _cachedCanReachValid;
|
||||
private float _cachedMaxSnap = -1f;
|
||||
|
||||
private void OnEnable() => EditorApplication.update += ThrottledRepaint;
|
||||
private void OnDisable() => EditorApplication.update -= ThrottledRepaint;
|
||||
// 退出 Play 期间:Application.isPlaying 仍为 true 但 PBWorld 已销毁,此时调 CanReach 会 NRE。
|
||||
// 收到 ExitingPlayMode 即停止一切运行时查询。
|
||||
private bool _exitingPlay;
|
||||
// 本帧是否绘制运行时区块——在 Layout 事件锁定、Repaint 复用,保证两趟控件数一致(否则 IMGUI 报错)。
|
||||
private bool _drawRuntimeThisFrame;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
EditorApplication.update += ThrottledRepaint;
|
||||
EditorApplication.playModeStateChanged += OnPlayModeChanged;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
EditorApplication.update -= ThrottledRepaint;
|
||||
EditorApplication.playModeStateChanged -= OnPlayModeChanged;
|
||||
}
|
||||
|
||||
private void OnPlayModeChanged(PlayModeStateChange s)
|
||||
{
|
||||
if (s == PlayModeStateChange.ExitingPlayMode) _exitingPlay = true;
|
||||
else if (s == PlayModeStateChange.EnteredPlayMode) _exitingPlay = false;
|
||||
}
|
||||
|
||||
// 定频请求重绘(不在 OnInspectorGUI 里每帧 Repaint,避免绑定到游戏帧率狂刷)
|
||||
private void ThrottledRepaint()
|
||||
@@ -58,7 +79,12 @@ namespace BaseGames.Editor
|
||||
}
|
||||
GUI.backgroundColor = prevBg;
|
||||
|
||||
if (!Application.isPlaying)
|
||||
// 是否绘制运行时区块的判定只在 Layout 事件更新,Repaint 复用同一结果——
|
||||
// 避免退出 Play 那一帧 isPlaying 在 Layout/Repaint 两趟间翻转导致控件数不一致而 IMGUI 报错。
|
||||
if (Event.current.type == EventType.Layout)
|
||||
_drawRuntimeThisFrame = Application.isPlaying && !_exitingPlay;
|
||||
|
||||
if (!_drawRuntimeThisFrame)
|
||||
{
|
||||
EditorGUILayout.Space(4f);
|
||||
EditorGUILayout.HelpBox("进入 Play 模式后此处显示实时巡逻调试信息(按钮在编辑期也可打印静态配置)。", MessageType.None);
|
||||
@@ -251,8 +277,9 @@ namespace BaseGames.Editor
|
||||
Row("到目标距离 / 到达半径", $"{dist:F2} / {loco.DebugArriveRadius:F2}{(arrived ? " (已到达)" : "")}",
|
||||
arrived ? Green : White);
|
||||
|
||||
// CanReach 会同步阻塞寻路 → 仅限频重算并缓存
|
||||
if (doHeavy && nav != null)
|
||||
// CanReach 会同步阻塞寻路 → 仅限频重算并缓存。
|
||||
// 额外守卫 !_exitingPlay && isPlaying:退出 Play 那一刻 PBWorld 已销毁,此时调会 NRE。
|
||||
if (doHeavy && nav != null && !_exitingPlay && Application.isPlaying)
|
||||
{
|
||||
_cachedCanReach = nav.CanReach(goal);
|
||||
_cachedCanReachValid = true;
|
||||
|
||||
Reference in New Issue
Block a user