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 Simulation;
|
||||
using StarForce;
|
||||
using UI;
|
||||
using UnityEngine;
|
||||
|
|
@ -20,12 +21,15 @@ public partial class GameEntry : MonoBehaviour
|
|||
public static HPBarComponent HPBar { get; private set; }
|
||||
|
||||
public static DamageTextComponent DamageText { get; private set; }
|
||||
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
public static RuntimeDebugPanelComponent RuntimeDebugPanel { get; private set; }
|
||||
#endif
|
||||
|
||||
public static EnemyManagerComponent EnemyManager { get; private set; }
|
||||
|
||||
public static SimulationWorld SimulationWorld { get; private set; }
|
||||
|
||||
public static SpriteCacheComponent SpriteCache { 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>();
|
||||
HPBar = UnityGameFramework.Runtime.GameEntry.GetComponent<HPBarComponent>();
|
||||
DamageText = UnityGameFramework.Runtime.GameEntry.GetComponent<DamageTextComponent>();
|
||||
if (DamageText == null && Base != null)
|
||||
{
|
||||
DamageText = Base.gameObject.AddComponent<DamageTextComponent>();
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
RuntimeDebugPanel = UnityGameFramework.Runtime.GameEntry.GetComponent<RuntimeDebugPanelComponent>();
|
||||
if (RuntimeDebugPanel == null && Base != null)
|
||||
{
|
||||
RuntimeDebugPanel = Base.gameObject.AddComponent<RuntimeDebugPanelComponent>();
|
||||
}
|
||||
#endif
|
||||
|
||||
EnemyManager = UnityGameFramework.Runtime.GameEntry.GetComponent<EnemyManagerComponent>();
|
||||
SimulationWorld = UnityGameFramework.Runtime.GameEntry.GetComponent<SimulationWorld>();
|
||||
SpriteCache = UnityGameFramework.Runtime.GameEntry.GetComponent<SpriteCacheComponent>();
|
||||
UIRouter = UnityGameFramework.Runtime.GameEntry.GetComponent<UIRouterComponent>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using Entity;
|
|||
using Entity.EntityData;
|
||||
using GameFramework.Event;
|
||||
using Procedure;
|
||||
using Simulation;
|
||||
using StarForce;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
|
@ -213,7 +214,17 @@ namespace CustomComponent
|
|||
{
|
||||
_currentEnemyCount++;
|
||||
enemy.SetTarget(_player);
|
||||
RemoveEnemyFromCache(enemy.Id);
|
||||
_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))
|
||||
|
|
@ -227,9 +238,41 @@ namespace CustomComponent
|
|||
if (e is HideEntityCompleteEventArgs ne)
|
||||
{
|
||||
if (ne.EntityGroup.Name == "Enemy")
|
||||
{
|
||||
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 CustomEvent;
|
||||
using DataTable;
|
||||
using Definition.Enum;
|
||||
using Entity;
|
||||
|
|
@ -24,11 +23,11 @@ namespace Procedure
|
|||
{
|
||||
public override bool UseNativeDialog => false;
|
||||
|
||||
private HudForm _hudForm = null;
|
||||
private bool _hudInitialized = false;
|
||||
private HudForm _hudForm;
|
||||
private bool _hudInitialized;
|
||||
|
||||
private IFsm<IProcedureManager> _procedureOwner = null;
|
||||
private PlayerData _currentPlayerData = null;
|
||||
private IFsm<IProcedureManager> _procedureOwner;
|
||||
private PlayerData _currentPlayerData;
|
||||
public int CurrentLevel = 1;
|
||||
|
||||
private GameStateType _currentGameState = GameStateType.None;
|
||||
|
|
@ -88,6 +87,7 @@ namespace Procedure
|
|||
base.OnEnter(procedureOwner);
|
||||
|
||||
_procedureOwner = procedureOwner;
|
||||
GameEntry.SimulationWorld?.Clear();
|
||||
|
||||
GameEntry.Event.Subscribe(OpenUIFormSuccessEventArgs.EventId, OpenUIFormSuccess);
|
||||
GameEntry.Event.Subscribe(ShowEntitySuccessEventArgs.EventId, ShowEntitySuccess);
|
||||
|
|
@ -135,6 +135,7 @@ namespace Procedure
|
|||
Player = null;
|
||||
|
||||
_procedureOwner = null;
|
||||
GameEntry.SimulationWorld?.Clear();
|
||||
|
||||
GameEntry.Event.Unsubscribe(OpenUIFormSuccessEventArgs.EventId, OpenUIFormSuccess);
|
||||
GameEntry.Event.Unsubscribe(ShowEntitySuccessEventArgs.EventId, ShowEntitySuccess);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace Simulation
|
||||
{
|
||||
public sealed class SimulationWorld
|
||||
public sealed class SimulationWorld : GameFrameworkComponent
|
||||
{
|
||||
private readonly List<EnemySimData> _enemies = new List<EnemySimData>();
|
||||
private readonly List<ProjectileSimData> _projectiles = new List<ProjectileSimData>();
|
||||
|
|
@ -24,6 +25,17 @@ namespace Simulation
|
|||
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)
|
||||
{
|
||||
if (!EnemyBinding.TryGetSimulationIndex(entityId, out int simulationIndex))
|
||||
|
|
@ -52,6 +64,17 @@ namespace Simulation
|
|||
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)
|
||||
{
|
||||
if (!ProjectileBinding.TryGetSimulationIndex(entityId, out int simulationIndex))
|
||||
|
|
@ -80,6 +103,17 @@ namespace Simulation
|
|||
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)
|
||||
{
|
||||
if (!PickupBinding.TryGetSimulationIndex(entityId, out int simulationIndex))
|
||||
|
|
|
|||
|
|
@ -241,6 +241,8 @@ Transform:
|
|||
- {fileID: 472081678}
|
||||
- {fileID: 2050832067}
|
||||
- {fileID: 534968532}
|
||||
- {fileID: 477326942}
|
||||
- {fileID: 1652245191}
|
||||
m_Father: {fileID: 1852670053}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &120093239
|
||||
|
|
@ -802,6 +804,50 @@ MonoBehaviour:
|
|||
m_EditorClassIdentifier:
|
||||
_pixelsPerUnit: 100
|
||||
_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
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
@ -1336,6 +1382,50 @@ MonoBehaviour:
|
|||
_hpBarItemTemplate: {fileID: 11414536, guid: 96d2e77dd9853514da336717bd5627c0, type: 3}
|
||||
_hpBarInstanceRoot: {fileID: 1454214587}
|
||||
_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
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
- 新建 `SimulationTickContext`(至少包含 `deltaTime`、`playerPosition`)。
|
||||
- 完成标准:工程可编译,场景运行行为与当前一致(只加结构,不切链路)。
|
||||
|
||||
- [ ] Checkpoint 2:敌人生命周期接入 Simulation(保持 GameFramework 生命周期不变)
|
||||
- [x] Checkpoint 2:敌人生命周期接入 Simulation(保持 GameFramework 生命周期不变)
|
||||
- 在敌人 `Show/Hide` 时同步注册/反注册到 `SimulationWorld` 与 `EntityBinding`。
|
||||
- `EnemyManagerComponent` 继续负责刷怪与实体显隐,不改外部调用方式。
|
||||
- 完成标准:敌人数量统计与当前一致,无重复注册、无悬空索引。
|
||||
|
|
|
|||
Loading…
Reference in New Issue