修复 GameStateBattle -> GameStateShop/LevelUp 时的敌人异常残留问题
用一个 _isStopped 布尔门替代 id 追踪: - OnReset 开头置 _isStopped = true - OnInit 置 _isStopped = false - OnShowEntitySuccess:只要 _isStopped 为真且是 Enemy 组,立即 HideEntity - SpawnEnemyAsync await 恢复后也补一道 _isStopped 检查(若 await 拿到了 enemy 且已停战,直接 hide 不注册)——双保险 为什么这样对:停战窗口(Shop/LevelUp)期间本就不该有任何敌人,所以"停战期间出生的敌人一律 hide"在语义上完全正确,且不受 await 同步抽空、id 复用、加载时序任何影响。
This commit is contained in:
parent
c111170bb0
commit
4250e48e22
|
|
@ -33,6 +33,11 @@ namespace SepCore.EnemyManager
|
|||
private Transform _player;
|
||||
private ISpawnPositionStrategy _spawnPositionStrategy;
|
||||
private CancellationTokenSource _spawnCts;
|
||||
// 停战标志。OnReset 置 true,OnInit 置 false。
|
||||
// ShowEntity 请求一旦发出,取消 await 并不能阻止框架真正创建实体,
|
||||
// 这些在途敌人会在 OnReset 之后才出生(fire ShowEntitySuccess)。
|
||||
// 此时 _isStopped 为真,由 OnShowEntitySuccess 在出生瞬间兜底 Hide 掉。
|
||||
private bool _isStopped;
|
||||
|
||||
public float SpawnRateScale => _spawnScheduler?.SpawnRateScale ?? 1f;
|
||||
public float BattleDuration => _duration;
|
||||
|
|
@ -49,11 +54,13 @@ namespace SepCore.EnemyManager
|
|||
_spawnCts = CancellationTokenSource.CreateLinkedTokenSource(destroyCancellationToken);
|
||||
|
||||
GameEntry.Event.Subscribe(HideEntityCompleteEventArgs.EventId, OnHideEntityComplete);
|
||||
GameEntry.Event.Subscribe(ShowEntitySuccessEventArgs.EventId, OnShowEntitySuccess);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
GameEntry.Event.Unsubscribe(HideEntityCompleteEventArgs.EventId, OnHideEntityComplete);
|
||||
GameEntry.Event.Unsubscribe(ShowEntitySuccessEventArgs.EventId, OnShowEntitySuccess);
|
||||
|
||||
_spawnCts?.Dispose();
|
||||
_spawnCts = null;
|
||||
|
|
@ -65,6 +72,8 @@ namespace SepCore.EnemyManager
|
|||
|
||||
public void OnInit(DRLevel level, Player player)
|
||||
{
|
||||
_isStopped = false;
|
||||
|
||||
_player = player != null ? player.CachedTransform : null;
|
||||
_spawnPositionStrategy = new RandomCircleSpawnStrategy(_spawnDistanceFromPlayer);
|
||||
|
||||
|
|
@ -93,11 +102,16 @@ namespace SepCore.EnemyManager
|
|||
|
||||
public void OnReset()
|
||||
{
|
||||
// 先置停战标志。Cancel() 会同步恢复在途的 SpawnEnemyAsync(enemy 拿不到引用,
|
||||
// 无法自行 hide),这些实体会延后出生,由 OnShowEntitySuccess 兜底。
|
||||
_isStopped = true;
|
||||
|
||||
_spawnCts.Cancel();
|
||||
_spawnCts.Dispose();
|
||||
_spawnCts = CancellationTokenSource.CreateLinkedTokenSource(destroyCancellationToken);
|
||||
|
||||
_spawnScheduler.Reset();
|
||||
|
||||
ClearEnemies();
|
||||
_currentSpawnEnemyId = 0;
|
||||
_currentLevel = 0;
|
||||
|
|
@ -113,6 +127,7 @@ namespace SepCore.EnemyManager
|
|||
|
||||
if (_enemyRegistry.Count >= _spawnEnemyMaxCount) return;
|
||||
int entityId = _currentSpawnEnemyId++;
|
||||
|
||||
var enemyData = EntityDataFactory.Create(entityId, enemyType, _currentLevel);
|
||||
enemyData.Position = _spawnPositionStrategy.GetSpawnPosition(_player);
|
||||
|
||||
|
|
@ -121,6 +136,8 @@ namespace SepCore.EnemyManager
|
|||
await _entity.ShowEnemyAsync(enemyData, cancellationToken: ct).SuppressCancellationThrow();
|
||||
if (isCanceled || ct.IsCancellationRequested || enemy == null || !enemy.Available)
|
||||
{
|
||||
// 取消通常发生在 OnReset 期间,此时实体往往尚未出生,enemy 为 null 无法 hide。
|
||||
// 真正的兜底在 OnShowEntitySuccess:停战后出生的敌人会被立即 hide。
|
||||
if (enemy != null && enemy.Available)
|
||||
{
|
||||
_entity.HideEntity(enemy);
|
||||
|
|
@ -129,6 +146,13 @@ namespace SepCore.EnemyManager
|
|||
return;
|
||||
}
|
||||
|
||||
// await 恢复时若已停战,说明这是漏网的在途敌人,立即 hide,不注册。
|
||||
if (_isStopped)
|
||||
{
|
||||
_entity.HideEntity(enemy);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_player != null)
|
||||
{
|
||||
enemy.SetTarget(_player);
|
||||
|
|
@ -172,6 +196,22 @@ namespace SepCore.EnemyManager
|
|||
}
|
||||
}
|
||||
|
||||
private void OnShowEntitySuccess(object sender, GameEventArgs e)
|
||||
{
|
||||
if (e is not ShowEntitySuccessEventArgs ne) return;
|
||||
if (ne.Entity.EntityGroup?.Name != EnemyGroupName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 停战窗口(Shop/LevelUp)期间不应存在任何敌人。OnReset 之前发出的在途
|
||||
// ShowEntity 请求会在此刻才真正出生,立即 hide 兜底。
|
||||
if (_isStopped)
|
||||
{
|
||||
_entity.HideEntity(ne.Entity.Id);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using SepCore.Entity;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.EnemyManager
|
||||
{
|
||||
|
|
@ -24,12 +23,8 @@ namespace SepCore.EnemyManager
|
|||
|
||||
public void Remove(int entityId)
|
||||
{
|
||||
if (!_enemyById.ContainsKey(entityId))
|
||||
{
|
||||
Debug.LogWarning($"EnemyRegistry: Attempt to remove non-existent entity id={entityId}");
|
||||
return;
|
||||
}
|
||||
|
||||
// 移除是幂等的。ClearEnemies 会同步清空 registry,而 HideEntity 的完成回调
|
||||
// 是异步的,晚几帧才到达,此时该 id 早已不在集合中,属正常情况,静默忽略即可。
|
||||
_enemyById.Remove(entityId);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -738,7 +738,7 @@ PrefabInstance:
|
|||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 11499388, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||
propertyPath: m_EditorResourceMode
|
||||
value: 0
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 11499388, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||
propertyPath: m_JsonHelperTypeName
|
||||
|
|
|
|||
Loading…
Reference in New Issue