110 lines
4.5 KiB
C#
110 lines
4.5 KiB
C#
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
|
|
}
|
|
}
|