Checkpoint 2:
- 调整 SimulationWorld 作为 GameFrameworkComponent 组件 - ProcedureGame 接入 SimulationWorld 生命周期(创建/清理)并在敌人 Show/Hide 时同步注册/反注册 - 增加 EnemySimData 构建与缓存去重移除,避免重复注册和悬空映射 - SimulationWorld 增加 UpsertEnemy/UpsertProjectile/UpsertPickup,支持幂等注册
This commit is contained in:
parent
3b8e0731f0
commit
83f8a356f7
|
|
@ -6,6 +6,7 @@
|
||||||
//------------------------------------------------------------
|
//------------------------------------------------------------
|
||||||
|
|
||||||
using CustomComponent;
|
using CustomComponent;
|
||||||
|
using Simulation;
|
||||||
using StarForce;
|
using StarForce;
|
||||||
using UI;
|
using UI;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
@ -20,12 +21,15 @@ public partial class GameEntry : MonoBehaviour
|
||||||
public static HPBarComponent HPBar { get; private set; }
|
public static HPBarComponent HPBar { get; private set; }
|
||||||
|
|
||||||
public static DamageTextComponent DamageText { get; private set; }
|
public static DamageTextComponent DamageText { get; private set; }
|
||||||
|
|
||||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||||
public static RuntimeDebugPanelComponent RuntimeDebugPanel { get; private set; }
|
public static RuntimeDebugPanelComponent RuntimeDebugPanel { get; private set; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public static EnemyManagerComponent EnemyManager { get; private set; }
|
public static EnemyManagerComponent EnemyManager { get; private set; }
|
||||||
|
|
||||||
|
public static SimulationWorld SimulationWorld { get; private set; }
|
||||||
|
|
||||||
public static SpriteCacheComponent SpriteCache { get; private set; }
|
public static SpriteCacheComponent SpriteCache { get; private set; }
|
||||||
|
|
||||||
public static UIRouterComponent UIRouter { get; private set; }
|
public static UIRouterComponent UIRouter { get; private set; }
|
||||||
|
|
@ -35,18 +39,13 @@ public partial class GameEntry : MonoBehaviour
|
||||||
BuiltinData = UnityGameFramework.Runtime.GameEntry.GetComponent<BuiltinDataComponent>();
|
BuiltinData = UnityGameFramework.Runtime.GameEntry.GetComponent<BuiltinDataComponent>();
|
||||||
HPBar = UnityGameFramework.Runtime.GameEntry.GetComponent<HPBarComponent>();
|
HPBar = UnityGameFramework.Runtime.GameEntry.GetComponent<HPBarComponent>();
|
||||||
DamageText = UnityGameFramework.Runtime.GameEntry.GetComponent<DamageTextComponent>();
|
DamageText = UnityGameFramework.Runtime.GameEntry.GetComponent<DamageTextComponent>();
|
||||||
if (DamageText == null && Base != null)
|
|
||||||
{
|
|
||||||
DamageText = Base.gameObject.AddComponent<DamageTextComponent>();
|
|
||||||
}
|
|
||||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||||
RuntimeDebugPanel = UnityGameFramework.Runtime.GameEntry.GetComponent<RuntimeDebugPanelComponent>();
|
RuntimeDebugPanel = UnityGameFramework.Runtime.GameEntry.GetComponent<RuntimeDebugPanelComponent>();
|
||||||
if (RuntimeDebugPanel == null && Base != null)
|
|
||||||
{
|
|
||||||
RuntimeDebugPanel = Base.gameObject.AddComponent<RuntimeDebugPanelComponent>();
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
EnemyManager = UnityGameFramework.Runtime.GameEntry.GetComponent<EnemyManagerComponent>();
|
EnemyManager = UnityGameFramework.Runtime.GameEntry.GetComponent<EnemyManagerComponent>();
|
||||||
|
SimulationWorld = UnityGameFramework.Runtime.GameEntry.GetComponent<SimulationWorld>();
|
||||||
SpriteCache = UnityGameFramework.Runtime.GameEntry.GetComponent<SpriteCacheComponent>();
|
SpriteCache = UnityGameFramework.Runtime.GameEntry.GetComponent<SpriteCacheComponent>();
|
||||||
UIRouter = UnityGameFramework.Runtime.GameEntry.GetComponent<UIRouterComponent>();
|
UIRouter = UnityGameFramework.Runtime.GameEntry.GetComponent<UIRouterComponent>();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using Entity;
|
||||||
using Entity.EntityData;
|
using Entity.EntityData;
|
||||||
using GameFramework.Event;
|
using GameFramework.Event;
|
||||||
using Procedure;
|
using Procedure;
|
||||||
|
using Simulation;
|
||||||
using StarForce;
|
using StarForce;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityGameFramework.Runtime;
|
using UnityGameFramework.Runtime;
|
||||||
|
|
@ -213,7 +214,17 @@ namespace CustomComponent
|
||||||
{
|
{
|
||||||
_currentEnemyCount++;
|
_currentEnemyCount++;
|
||||||
enemy.SetTarget(_player);
|
enemy.SetTarget(_player);
|
||||||
|
RemoveEnemyFromCache(enemy.Id);
|
||||||
_enemies.Add(enemy);
|
_enemies.Add(enemy);
|
||||||
|
|
||||||
|
if (ne.UserData is EnemyData enemyData)
|
||||||
|
{
|
||||||
|
GameEntry.SimulationWorld?.UpsertEnemy(CreateEnemySimData(enemy, enemyData));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GameEntry.SimulationWorld?.UpsertEnemy(CreateEnemySimData(enemy, null));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ne.EntityLogicType == typeof(Player))
|
if (ne.EntityLogicType == typeof(Player))
|
||||||
|
|
@ -228,7 +239,39 @@ namespace CustomComponent
|
||||||
{
|
{
|
||||||
if (ne.EntityGroup.Name == "Enemy")
|
if (ne.EntityGroup.Name == "Enemy")
|
||||||
{
|
{
|
||||||
_currentEnemyCount--;
|
if (_currentEnemyCount > 0)
|
||||||
|
{
|
||||||
|
_currentEnemyCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveEnemyFromCache(ne.EntityId);
|
||||||
|
GameEntry.SimulationWorld?.RemoveEnemyByEntityId(ne.EntityId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static EnemySimData CreateEnemySimData(EnemyBase enemy, EnemyData enemyData)
|
||||||
|
{
|
||||||
|
return new EnemySimData
|
||||||
|
{
|
||||||
|
EntityId = enemy.Id,
|
||||||
|
Position = enemy.CachedTransform.position,
|
||||||
|
Forward = enemy.CachedTransform.forward,
|
||||||
|
Speed = enemyData != null ? enemyData.SpeedBase : 0f,
|
||||||
|
AttackRange = 1f,
|
||||||
|
TargetType = 0,
|
||||||
|
State = 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveEnemyFromCache(int entityId)
|
||||||
|
{
|
||||||
|
for (int i = _enemies.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
EntityBase cachedEnemy = _enemies[i];
|
||||||
|
if (cachedEnemy == null || cachedEnemy.Id == entityId)
|
||||||
|
{
|
||||||
|
_enemies.RemoveAt(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using CustomEvent;
|
|
||||||
using DataTable;
|
using DataTable;
|
||||||
using Definition.Enum;
|
using Definition.Enum;
|
||||||
using Entity;
|
using Entity;
|
||||||
|
|
@ -24,11 +23,11 @@ namespace Procedure
|
||||||
{
|
{
|
||||||
public override bool UseNativeDialog => false;
|
public override bool UseNativeDialog => false;
|
||||||
|
|
||||||
private HudForm _hudForm = null;
|
private HudForm _hudForm;
|
||||||
private bool _hudInitialized = false;
|
private bool _hudInitialized;
|
||||||
|
|
||||||
private IFsm<IProcedureManager> _procedureOwner = null;
|
private IFsm<IProcedureManager> _procedureOwner;
|
||||||
private PlayerData _currentPlayerData = null;
|
private PlayerData _currentPlayerData;
|
||||||
public int CurrentLevel = 1;
|
public int CurrentLevel = 1;
|
||||||
|
|
||||||
private GameStateType _currentGameState = GameStateType.None;
|
private GameStateType _currentGameState = GameStateType.None;
|
||||||
|
|
@ -88,6 +87,7 @@ namespace Procedure
|
||||||
base.OnEnter(procedureOwner);
|
base.OnEnter(procedureOwner);
|
||||||
|
|
||||||
_procedureOwner = procedureOwner;
|
_procedureOwner = procedureOwner;
|
||||||
|
GameEntry.SimulationWorld?.Clear();
|
||||||
|
|
||||||
GameEntry.Event.Subscribe(OpenUIFormSuccessEventArgs.EventId, OpenUIFormSuccess);
|
GameEntry.Event.Subscribe(OpenUIFormSuccessEventArgs.EventId, OpenUIFormSuccess);
|
||||||
GameEntry.Event.Subscribe(ShowEntitySuccessEventArgs.EventId, ShowEntitySuccess);
|
GameEntry.Event.Subscribe(ShowEntitySuccessEventArgs.EventId, ShowEntitySuccess);
|
||||||
|
|
@ -135,6 +135,7 @@ namespace Procedure
|
||||||
Player = null;
|
Player = null;
|
||||||
|
|
||||||
_procedureOwner = null;
|
_procedureOwner = null;
|
||||||
|
GameEntry.SimulationWorld?.Clear();
|
||||||
|
|
||||||
GameEntry.Event.Unsubscribe(OpenUIFormSuccessEventArgs.EventId, OpenUIFormSuccess);
|
GameEntry.Event.Unsubscribe(OpenUIFormSuccessEventArgs.EventId, OpenUIFormSuccess);
|
||||||
GameEntry.Event.Unsubscribe(ShowEntitySuccessEventArgs.EventId, ShowEntitySuccess);
|
GameEntry.Event.Unsubscribe(ShowEntitySuccessEventArgs.EventId, ShowEntitySuccess);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using UnityGameFramework.Runtime;
|
||||||
|
|
||||||
namespace Simulation
|
namespace Simulation
|
||||||
{
|
{
|
||||||
public sealed class SimulationWorld
|
public sealed class SimulationWorld : GameFrameworkComponent
|
||||||
{
|
{
|
||||||
private readonly List<EnemySimData> _enemies = new List<EnemySimData>();
|
private readonly List<EnemySimData> _enemies = new List<EnemySimData>();
|
||||||
private readonly List<ProjectileSimData> _projectiles = new List<ProjectileSimData>();
|
private readonly List<ProjectileSimData> _projectiles = new List<ProjectileSimData>();
|
||||||
|
|
@ -24,6 +25,17 @@ namespace Simulation
|
||||||
return simulationIndex;
|
return simulationIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int UpsertEnemy(in EnemySimData simData)
|
||||||
|
{
|
||||||
|
if (EnemyBinding.TryGetSimulationIndex(simData.EntityId, out int simulationIndex))
|
||||||
|
{
|
||||||
|
_enemies[simulationIndex] = simData;
|
||||||
|
return simulationIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AddEnemy(simData);
|
||||||
|
}
|
||||||
|
|
||||||
public bool RemoveEnemyByEntityId(int entityId)
|
public bool RemoveEnemyByEntityId(int entityId)
|
||||||
{
|
{
|
||||||
if (!EnemyBinding.TryGetSimulationIndex(entityId, out int simulationIndex))
|
if (!EnemyBinding.TryGetSimulationIndex(entityId, out int simulationIndex))
|
||||||
|
|
@ -52,6 +64,17 @@ namespace Simulation
|
||||||
return simulationIndex;
|
return simulationIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int UpsertProjectile(in ProjectileSimData simData)
|
||||||
|
{
|
||||||
|
if (ProjectileBinding.TryGetSimulationIndex(simData.EntityId, out int simulationIndex))
|
||||||
|
{
|
||||||
|
_projectiles[simulationIndex] = simData;
|
||||||
|
return simulationIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AddProjectile(simData);
|
||||||
|
}
|
||||||
|
|
||||||
public bool RemoveProjectileByEntityId(int entityId)
|
public bool RemoveProjectileByEntityId(int entityId)
|
||||||
{
|
{
|
||||||
if (!ProjectileBinding.TryGetSimulationIndex(entityId, out int simulationIndex))
|
if (!ProjectileBinding.TryGetSimulationIndex(entityId, out int simulationIndex))
|
||||||
|
|
@ -80,6 +103,17 @@ namespace Simulation
|
||||||
return simulationIndex;
|
return simulationIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int UpsertPickup(in PickupSimData simData)
|
||||||
|
{
|
||||||
|
if (PickupBinding.TryGetSimulationIndex(simData.EntityId, out int simulationIndex))
|
||||||
|
{
|
||||||
|
_pickups[simulationIndex] = simData;
|
||||||
|
return simulationIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AddPickup(simData);
|
||||||
|
}
|
||||||
|
|
||||||
public bool RemovePickupByEntityId(int entityId)
|
public bool RemovePickupByEntityId(int entityId)
|
||||||
{
|
{
|
||||||
if (!PickupBinding.TryGetSimulationIndex(entityId, out int simulationIndex))
|
if (!PickupBinding.TryGetSimulationIndex(entityId, out int simulationIndex))
|
||||||
|
|
|
||||||
|
|
@ -241,6 +241,8 @@ Transform:
|
||||||
- {fileID: 472081678}
|
- {fileID: 472081678}
|
||||||
- {fileID: 2050832067}
|
- {fileID: 2050832067}
|
||||||
- {fileID: 534968532}
|
- {fileID: 534968532}
|
||||||
|
- {fileID: 477326942}
|
||||||
|
- {fileID: 1652245191}
|
||||||
m_Father: {fileID: 1852670053}
|
m_Father: {fileID: 1852670053}
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!1 &120093239
|
--- !u!1 &120093239
|
||||||
|
|
@ -802,6 +804,50 @@ MonoBehaviour:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
_pixelsPerUnit: 100
|
_pixelsPerUnit: 100
|
||||||
_defaultPivot: {x: 0.5, y: 0.5}
|
_defaultPivot: {x: 0.5, y: 0.5}
|
||||||
|
--- !u!1 &477326941
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 477326942}
|
||||||
|
- component: {fileID: 477326943}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: RuntimeDebugPanel
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &477326942
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 477326941}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 119167776}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &477326943
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 477326941}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 1d8ada5157a04921a6e543a040e57960, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
--- !u!1 &513208572
|
--- !u!1 &513208572
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|
@ -1336,6 +1382,50 @@ MonoBehaviour:
|
||||||
_hpBarItemTemplate: {fileID: 11414536, guid: 96d2e77dd9853514da336717bd5627c0, type: 3}
|
_hpBarItemTemplate: {fileID: 11414536, guid: 96d2e77dd9853514da336717bd5627c0, type: 3}
|
||||||
_hpBarInstanceRoot: {fileID: 1454214587}
|
_hpBarInstanceRoot: {fileID: 1454214587}
|
||||||
_instancePoolCapacity: 16
|
_instancePoolCapacity: 16
|
||||||
|
--- !u!1 &1652245190
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 1652245191}
|
||||||
|
- component: {fileID: 1652245192}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: SimulationWorld
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &1652245191
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1652245190}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 119167776}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &1652245192
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1652245190}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 8a558ebbc9cb4d94946ac9f4f27914d8, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
--- !u!1 &1852670052
|
--- !u!1 &1852670052
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@
|
||||||
- 新建 `SimulationTickContext`(至少包含 `deltaTime`、`playerPosition`)。
|
- 新建 `SimulationTickContext`(至少包含 `deltaTime`、`playerPosition`)。
|
||||||
- 完成标准:工程可编译,场景运行行为与当前一致(只加结构,不切链路)。
|
- 完成标准:工程可编译,场景运行行为与当前一致(只加结构,不切链路)。
|
||||||
|
|
||||||
- [ ] Checkpoint 2:敌人生命周期接入 Simulation(保持 GameFramework 生命周期不变)
|
- [x] Checkpoint 2:敌人生命周期接入 Simulation(保持 GameFramework 生命周期不变)
|
||||||
- 在敌人 `Show/Hide` 时同步注册/反注册到 `SimulationWorld` 与 `EntityBinding`。
|
- 在敌人 `Show/Hide` 时同步注册/反注册到 `SimulationWorld` 与 `EntityBinding`。
|
||||||
- `EnemyManagerComponent` 继续负责刷怪与实体显隐,不改外部调用方式。
|
- `EnemyManagerComponent` 继续负责刷怪与实体显隐,不改外部调用方式。
|
||||||
- 完成标准:敌人数量统计与当前一致,无重复注册、无悬空索引。
|
- 完成标准:敌人数量统计与当前一致,无重复注册、无悬空索引。
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue