using SepCore.Debugger; using UnityEngine; using UnityGameFramework.Runtime; namespace SepCore.Simulation { public sealed partial class SimulationWorld : GameFrameworkComponent, ISimulationWorld { // Partial layout: // - SimulationWorld.cs: 核心状态、常量和 Unity 生命周期入口点。 // - SimulationWorld.RuntimeModules.cs: 运行时域对象、配置和状态代理。 // - SimulationWorld.SimEntityState.cs: 模拟状态的增删改查和生命周期注册。 // - SimulationWorld.EntityToSimData.cs: Unity 实体与组件列/快照之间的边界转换。 // - SimulationWorld.EntitySync.cs: GameFramework 实体 show/hide 事件桥。 // - SimulationWorld.TargetSelectionSpatialIndex.cs: 最近敌空间索引查询。 // - SimulationWorld.PlayerMovement.cs: 玩家模拟移动输入与步进。 // - Components/*: 敌人/投射物/掉落物 SoA 组件列与存储。 // - Presentation/SimulationWorld.TransformSync.cs: late-update transform 同步桥。 // - Presentation/SimulationWorld.HitPresentation.cs: 投射物命中事件表现桥。 // - DataChannel/*: Job 通道与帧间临时状态。 // - Systems/*: 独立数据并行系统(移动/分离/碰撞查询)。 // - Jobs/*: 模拟管线编排、碰撞调度与结算。 // - JobStruct/*: 面向 job 的瞬时数据结构。 // 模拟数据以组件列(SoA)为唯一存储,XxxSimData 只作为生成/查询边界的快照结构。 private const float MinFixedStepSeconds = 0.0001f; private const double FixedStepEpsilonScale = 1e-4; [Header("固定步长模拟")] [Tooltip("开启后按固定步长累积时间,一帧内可能执行多次模拟步进。")] [SerializeField] private bool _fixedStepEnabled = true; [Tooltip("固定步长(秒)。")] [SerializeField] private float _fixedStepSeconds = 1f / 60f; private double _fixedStepAccumulator; private EntitySync _entitySync; private TransformSync _transformSync; private HitPresentation _hitPresentation; #region Lifecycle protected override void Awake() { base.Awake(); _entitySync = new EntitySync(this); _transformSync = new TransformSync(this); _hitPresentation = new HitPresentation(this); InitializeJobDataChannels(); } private void Start() { _entitySync?.OnStart(); _hitPresentation?.OnStart(); } public void Tick(in SimulationTickContext context) { if (!_fixedStepEnabled) { TickSimulationStep(context.PlayerPosition, context.DeltaTime); return; } double fixedStep = Mathf.Max(MinFixedStepSeconds, _fixedStepSeconds); double stepEpsilon = fixedStep * FixedStepEpsilonScale; _fixedStepAccumulator += context.DeltaTime; while (_fixedStepAccumulator + stepEpsilon >= fixedStep) { TickSimulationStep(context.PlayerPosition, (float)fixedStep); _fixedStepAccumulator -= fixedStep; if (_fixedStepAccumulator < 0d) { _fixedStepAccumulator = 0d; } } } private void TickSimulationStep(Vector3 fallbackPlayerPosition, float deltaTime) { Vector3 playerPosition = ResolvePlayerPositionForTick(fallbackPlayerPosition, deltaTime); SimulationTickContext resolvedContext = new SimulationTickContext(deltaTime, playerPosition); using (CustomProfilerMarker.TickEnemies.Auto()) { TickSimulationPipeline(in resolvedContext); } } private void OnDestroy() { _hitPresentation?.OnDestroy(); _entitySync?.OnDestroy(); _entitySync = null; _transformSync = null; _hitPresentation = null; DisposeJobDataChannels(); } private void LateUpdate() { _transformSync?.OnLateUpdate(); } #endregion } }