From 83f8a356f70f86e6ddef3905c4919743248205c9 Mon Sep 17 00:00:00 2001 From: SepComet <202308010230@stu.csust.edu.cn> Date: Fri, 20 Feb 2026 18:47:00 +0800 Subject: [PATCH] =?UTF-8?q?Checkpoint=202=EF=BC=9A=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20SimulationWorld=20=E4=BD=9C=E4=B8=BA=20GameFramewor?= =?UTF-8?q?kComponent=20=E7=BB=84=E4=BB=B6=20-=20ProcedureGame=20=E6=8E=A5?= =?UTF-8?q?=E5=85=A5=20SimulationWorld=20=E7=94=9F=E5=91=BD=E5=91=A8?= =?UTF-8?q?=E6=9C=9F=EF=BC=88=E5=88=9B=E5=BB=BA/=E6=B8=85=E7=90=86?= =?UTF-8?q?=EF=BC=89=E5=B9=B6=E5=9C=A8=E6=95=8C=E4=BA=BA=20Show/Hide=20?= =?UTF-8?q?=E6=97=B6=E5=90=8C=E6=AD=A5=E6=B3=A8=E5=86=8C/=E5=8F=8D?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=20-=20=E5=A2=9E=E5=8A=A0=20EnemySimData=20?= =?UTF-8?q?=E6=9E=84=E5=BB=BA=E4=B8=8E=E7=BC=93=E5=AD=98=E5=8E=BB=E9=87=8D?= =?UTF-8?q?=E7=A7=BB=E9=99=A4=EF=BC=8C=E9=81=BF=E5=85=8D=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=E5=92=8C=E6=82=AC=E7=A9=BA=E6=98=A0=E5=B0=84?= =?UTF-8?q?=20-=20SimulationWorld=20=E5=A2=9E=E5=8A=A0=20UpsertEnemy/Upser?= =?UTF-8?q?tProjectile/UpsertPickup=EF=BC=8C=E6=94=AF=E6=8C=81=E5=B9=82?= =?UTF-8?q?=E7=AD=89=E6=B3=A8=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GameMain/Scripts/Base/GameEntry.Custom.cs | 21 +++-- .../EnemyManager/EnemyManagerComponent.cs | 47 +++++++++- .../Scripts/Procedure/Game/ProcedureGame.cs | 11 +-- .../Scripts/Simulation/SimulationWorld.cs | 36 +++++++- Assets/Launcher.unity | 90 +++++++++++++++++++ docs/TodoList.md | 2 +- 6 files changed, 187 insertions(+), 20 deletions(-) diff --git a/Assets/GameMain/Scripts/Base/GameEntry.Custom.cs b/Assets/GameMain/Scripts/Base/GameEntry.Custom.cs index 456e71c..41ac84e 100644 --- a/Assets/GameMain/Scripts/Base/GameEntry.Custom.cs +++ b/Assets/GameMain/Scripts/Base/GameEntry.Custom.cs @@ -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,19 +39,14 @@ public partial class GameEntry : MonoBehaviour BuiltinData = UnityGameFramework.Runtime.GameEntry.GetComponent(); HPBar = UnityGameFramework.Runtime.GameEntry.GetComponent(); DamageText = UnityGameFramework.Runtime.GameEntry.GetComponent(); - if (DamageText == null && Base != null) - { - DamageText = Base.gameObject.AddComponent(); - } + #if UNITY_EDITOR || DEVELOPMENT_BUILD RuntimeDebugPanel = UnityGameFramework.Runtime.GameEntry.GetComponent(); - if (RuntimeDebugPanel == null && Base != null) - { - RuntimeDebugPanel = Base.gameObject.AddComponent(); - } #endif + EnemyManager = UnityGameFramework.Runtime.GameEntry.GetComponent(); + SimulationWorld = UnityGameFramework.Runtime.GameEntry.GetComponent(); SpriteCache = UnityGameFramework.Runtime.GameEntry.GetComponent(); UIRouter = UnityGameFramework.Runtime.GameEntry.GetComponent(); } -} +} \ No newline at end of file diff --git a/Assets/GameMain/Scripts/CustomComponent/EnemyManager/EnemyManagerComponent.cs b/Assets/GameMain/Scripts/CustomComponent/EnemyManager/EnemyManagerComponent.cs index 2bc455a..ac2e413 100644 --- a/Assets/GameMain/Scripts/CustomComponent/EnemyManager/EnemyManagerComponent.cs +++ b/Assets/GameMain/Scripts/CustomComponent/EnemyManager/EnemyManagerComponent.cs @@ -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)) @@ -228,11 +239,43 @@ namespace CustomComponent { 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); } } } #endregion } -} \ No newline at end of file +} diff --git a/Assets/GameMain/Scripts/Procedure/Game/ProcedureGame.cs b/Assets/GameMain/Scripts/Procedure/Game/ProcedureGame.cs index 01dc50f..bcb12aa 100644 --- a/Assets/GameMain/Scripts/Procedure/Game/ProcedureGame.cs +++ b/Assets/GameMain/Scripts/Procedure/Game/ProcedureGame.cs @@ -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 _procedureOwner = null; - private PlayerData _currentPlayerData = null; + private IFsm _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); diff --git a/Assets/GameMain/Scripts/Simulation/SimulationWorld.cs b/Assets/GameMain/Scripts/Simulation/SimulationWorld.cs index 856d916..3c0fb1a 100644 --- a/Assets/GameMain/Scripts/Simulation/SimulationWorld.cs +++ b/Assets/GameMain/Scripts/Simulation/SimulationWorld.cs @@ -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 _enemies = new List(); private readonly List _projectiles = new List(); @@ -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)) diff --git a/Assets/Launcher.unity b/Assets/Launcher.unity index abbaee2..d990e43 100644 --- a/Assets/Launcher.unity +++ b/Assets/Launcher.unity @@ -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 diff --git a/docs/TodoList.md b/docs/TodoList.md index b6e8885..387be5d 100644 --- a/docs/TodoList.md +++ b/docs/TodoList.md @@ -32,7 +32,7 @@ - 新建 `SimulationTickContext`(至少包含 `deltaTime`、`playerPosition`)。 - 完成标准:工程可编译,场景运行行为与当前一致(只加结构,不切链路)。 -- [ ] Checkpoint 2:敌人生命周期接入 Simulation(保持 GameFramework 生命周期不变) +- [x] Checkpoint 2:敌人生命周期接入 Simulation(保持 GameFramework 生命周期不变) - 在敌人 `Show/Hide` 时同步注册/反注册到 `SimulationWorld` 与 `EntityBinding`。 - `EnemyManagerComponent` 继续负责刷怪与实体显隐,不改外部调用方式。 - 完成标准:敌人数量统计与当前一致,无重复注册、无悬空索引。