简单重构拆分 SimulationWorld

This commit is contained in:
2026-09-18 17:43:41 +08:00
parent 1e4d3ef8d7
commit 92e1ea0d55
109 changed files with 2605 additions and 1817 deletions
@@ -1,4 +1,5 @@
using SepCore.Entity;
using UnityEngine;
namespace SepCore.Simulation
{
@@ -16,11 +17,8 @@ namespace SepCore.Simulation
_areaCollisionRequests.Clear();
_areaCollisionHitEvents.Clear();
_areaCollisionHitDedupKeys.Clear();
_fixedStepAccumulator = 0d;
ClearJobDataChannels();
EnemyBinding.Clear();
ProjectileBinding.Clear();
PickupBinding.Clear();
ClearPlayerMovementState();
}
@@ -28,46 +26,96 @@ namespace SepCore.Simulation
#region Enemy Simulation State
private int AddEnemy(in EnemySimData simData)
{
int simulationIndex = _enemies.Count;
_enemies.Add(simData);
EnemyBinding.Bind(simData.EntityId, simulationIndex);
OnEnemyAddedToSeparationTemporalBuffers();
MarkEnemyTargetSpatialIndexDirty();
return simulationIndex;
}
public int EnemyCount => _enemies.Count;
private int UpsertEnemy(in EnemySimData simData)
public bool TryGetEnemySnapshot(int entityId, out EnemySimData snapshot)
{
if (!EnemyBinding.TryGetSimulationIndex(simData.EntityId, out int simulationIndex))
if (!_enemies.TryGetSimulationIndex(entityId, out int index))
{
return AddEnemy(simData);
snapshot = default;
return false;
}
_enemies[simulationIndex] = simData;
EnemyTransformSim transform = _enemies.Transform[index];
EnemyMoveInputSim moveInput = _enemies.MoveInput[index];
EnemyMoveConfigSim moveConfig = _enemies.MoveConfig[index];
EnemyAttackSim attack = _enemies.Attack[index];
EnemyBehaviorSim behavior = _enemies.Behavior[index];
snapshot = new EnemySimData
{
EntityId = entityId,
Position = ToVector3(transform.Position),
Forward = ToVector3(transform.Forward),
Rotation = ToQuaternion(transform.Rotation),
Speed = moveInput.Speed,
AttackRange = attack.AttackRange,
AvoidEnemyOverlap = moveConfig.AvoidOverlap,
EnemyBodyRadius = moveConfig.BodyRadius,
SeparationIterations = moveConfig.SeparationIterations,
State = behavior.State
};
return true;
}
private int AddEnemy(in EnemySimData simData)
{
InitializeJobDataChannels();
int index = _enemies.Add(
new EnemyIdentitySim { EntityId = simData.EntityId },
new EnemyTransformSim
{
Position = ToFloat3(simData.Position),
Forward = ToFloat3(simData.Forward),
Rotation = ToQuaternion(simData.Rotation)
},
new EnemyMoveInputSim { Speed = simData.Speed },
new EnemyMoveConfigSim
{
AvoidOverlap = simData.AvoidEnemyOverlap,
BodyRadius = simData.EnemyBodyRadius,
SeparationIterations = simData.SeparationIterations
},
new EnemyAttackSim { AttackRange = simData.AttackRange },
new EnemyBehaviorSim { State = simData.State });
MarkEnemyTargetSpatialIndexDirty();
return simulationIndex;
return index;
}
internal int UpsertEnemy(in EnemySimData simData)
{
if (!_enemies.TryGetSimulationIndex(simData.EntityId, out int index))
{
return AddEnemy(in simData);
}
_enemies.Identity[index] = new EnemyIdentitySim { EntityId = simData.EntityId };
_enemies.Transform[index] = new EnemyTransformSim
{
Position = ToFloat3(simData.Position),
Forward = ToFloat3(simData.Forward),
Rotation = ToQuaternion(simData.Rotation)
};
_enemies.MoveInput[index] = new EnemyMoveInputSim { Speed = simData.Speed };
_enemies.MoveConfig[index] = new EnemyMoveConfigSim
{
AvoidOverlap = simData.AvoidEnemyOverlap,
BodyRadius = simData.EnemyBodyRadius,
SeparationIterations = simData.SeparationIterations
};
_enemies.Attack[index] = new EnemyAttackSim { AttackRange = simData.AttackRange };
_enemies.Behavior[index] = new EnemyBehaviorSim { State = simData.State };
MarkEnemyTargetSpatialIndexDirty();
return index;
}
private bool RemoveEnemyByEntityId(int entityId)
{
if (!EnemyBinding.TryGetSimulationIndex(entityId, out int simulationIndex))
if (!_enemies.RemoveByEntityId(entityId))
{
return false;
}
int lastIndex = _enemies.Count - 1;
if (simulationIndex != lastIndex)
{
EnemySimData movedData = _enemies[lastIndex];
_enemies[simulationIndex] = movedData;
EnemyBinding.RemapIndex(movedData.EntityId, simulationIndex);
}
_enemies.RemoveAt(lastIndex);
OnEnemyRemovedFromSeparationTemporalBuffers(simulationIndex);
EnemyBinding.UnbindByEntityId(entityId);
MarkEnemyTargetSpatialIndexDirty();
return true;
}
@@ -88,85 +136,122 @@ namespace SepCore.Simulation
RemoveEnemyByEntityId(entityId);
}
private bool TryGetEnemyData(int entityId, out EnemySimData enemyData)
{
if (!EnemyBinding.TryGetSimulationIndex(entityId, out int simulationIndex) || simulationIndex < 0 ||
simulationIndex >= _enemies.Count)
{
enemyData = default;
return false;
}
enemyData = _enemies[simulationIndex];
return true;
}
public void SyncEnemyMovementInput(int entityId, bool isMoving, in UnityEngine.Vector3 direction, float speed,
public void SyncEnemyMovementInput(int entityId, bool isMoving, in Vector3 direction, float speed,
bool avoidEnemyOverlap, float enemyBodyRadius, int separationIterations)
{
if (!EnemyBinding.TryGetSimulationIndex(entityId, out int simulationIndex) || simulationIndex < 0 ||
simulationIndex >= _enemies.Count)
if (!_enemies.TryGetSimulationIndex(entityId, out int index))
{
return;
}
EnemySimData enemyData = _enemies[simulationIndex];
enemyData.Speed = isMoving ? UnityEngine.Mathf.Max(0f, speed) : 0f;
enemyData.AvoidEnemyOverlap = avoidEnemyOverlap;
enemyData.EnemyBodyRadius = UnityEngine.Mathf.Max(0.01f, enemyBodyRadius);
enemyData.SeparationIterations = UnityEngine.Mathf.Max(1, separationIterations);
UnityEngine.Vector3 planarDirection = direction;
planarDirection.y = 0f;
if (planarDirection.sqrMagnitude > UnityEngine.Mathf.Epsilon)
_enemies.MoveInput[index] = new EnemyMoveInputSim
{
enemyData.Forward = planarDirection.normalized;
}
Speed = isMoving ? Mathf.Max(0f, speed) : 0f
};
_enemies.MoveConfig[index] = new EnemyMoveConfigSim
{
AvoidOverlap = avoidEnemyOverlap,
BodyRadius = Mathf.Max(0.01f, enemyBodyRadius),
SeparationIterations = Mathf.Max(1, separationIterations)
};
_enemies[simulationIndex] = enemyData;
Vector3 planarDirection = direction;
planarDirection.y = 0f;
if (planarDirection.sqrMagnitude > Mathf.Epsilon)
{
planarDirection.Normalize();
EnemyTransformSim transform = _enemies.Transform[index];
transform.Forward = ToFloat3(planarDirection);
_enemies.Transform[index] = transform;
}
}
#endregion
#region Projectile Simulation State
private int AddProjectile(in ProjectileSimData simData)
{
int simulationIndex = _projectiles.Count;
_projectiles.Add(simData);
ProjectileBinding.Bind(simData.EntityId, simulationIndex);
return simulationIndex;
}
public int ProjectileCount => _projectiles.Count;
private int UpsertProjectile(in ProjectileSimData simData)
public bool TryGetProjectileSnapshot(int entityId, out ProjectileSimData snapshot)
{
if (!ProjectileBinding.TryGetSimulationIndex(simData.EntityId, out int simulationIndex))
if (!_projectiles.TryGetSimulationIndex(entityId, out int index))
{
return AddProjectile(simData);
snapshot = default;
return false;
}
_projectiles[simulationIndex] = simData;
return simulationIndex;
ProjectileIdentitySim identity = _projectiles.Identity[index];
ProjectileTransformSim transform = _projectiles.Transform[index];
ProjectileVelocitySim velocity = _projectiles.Velocity[index];
ProjectileLifeSim life = _projectiles.Life[index];
snapshot = new ProjectileSimData
{
EntityId = identity.EntityId,
OwnerEntityId = identity.OwnerEntityId,
Position = ToVector3(transform.Position),
Forward = ToVector3(transform.Forward),
Velocity = ToVector3(velocity.Velocity),
LifeTime = life.LifeTime,
Age = life.Age,
Active = life.Active
};
return true;
}
private int AddProjectile(in ProjectileSimData simData)
{
InitializeJobDataChannels();
return _projectiles.Add(
new ProjectileIdentitySim
{
EntityId = simData.EntityId,
OwnerEntityId = simData.OwnerEntityId
},
new ProjectileTransformSim
{
Position = ToFloat3(simData.Position),
Forward = ToFloat3(simData.Forward)
},
new ProjectileVelocitySim { Velocity = ToFloat3(simData.Velocity) },
new ProjectileLifeSim
{
Age = simData.Age,
LifeTime = simData.LifeTime,
Active = simData.Active
});
}
internal int UpsertProjectile(in ProjectileSimData simData)
{
if (!_projectiles.TryGetSimulationIndex(simData.EntityId, out int index))
{
return AddProjectile(in simData);
}
_projectiles.Identity[index] = new ProjectileIdentitySim
{
EntityId = simData.EntityId,
OwnerEntityId = simData.OwnerEntityId
};
_projectiles.Transform[index] = new ProjectileTransformSim
{
Position = ToFloat3(simData.Position),
Forward = ToFloat3(simData.Forward)
};
_projectiles.Velocity[index] = new ProjectileVelocitySim { Velocity = ToFloat3(simData.Velocity) };
_projectiles.Life[index] = new ProjectileLifeSim
{
Age = simData.Age,
LifeTime = simData.LifeTime,
Active = simData.Active
};
return index;
}
private bool RemoveProjectileByEntityId(int entityId)
{
if (!ProjectileBinding.TryGetSimulationIndex(entityId, out int simulationIndex))
{
return false;
}
int lastIndex = _projectiles.Count - 1;
if (simulationIndex != lastIndex)
{
ProjectileSimData movedData = _projectiles[lastIndex];
_projectiles[simulationIndex] = movedData;
ProjectileBinding.RemapIndex(movedData.EntityId, simulationIndex);
}
_projectiles.RemoveAt(lastIndex);
ProjectileBinding.UnbindByEntityId(entityId);
return true;
return _projectiles.RemoveByEntityId(entityId);
}
private void RegisterProjectileLifecycle(EntityBase projectileEntity, object userData)
@@ -188,43 +273,66 @@ namespace SepCore.Simulation
#region Pickup Simulation State
private int AddPickup(in PickupSimData simData)
{
int simulationIndex = _pickups.Count;
_pickups.Add(simData);
PickupBinding.Bind(simData.EntityId, simulationIndex);
return simulationIndex;
}
public int PickupCount => _pickups.Count;
private int UpsertPickup(in PickupSimData simData)
public bool TryGetPickupSnapshot(int entityId, out PickupSimData snapshot)
{
if (!PickupBinding.TryGetSimulationIndex(simData.EntityId, out int simulationIndex))
if (!_pickups.TryGetSimulationIndex(entityId, out int index))
{
return AddPickup(simData);
snapshot = default;
return false;
}
_pickups[simulationIndex] = simData;
return simulationIndex;
PickupTransformSim transform = _pickups.Transform[index];
PickupRadiusSim radius = _pickups.Radius[index];
PickupStateSim state = _pickups.State[index];
snapshot = new PickupSimData
{
EntityId = entityId,
Position = ToVector3(transform.Position),
PickupRadius = radius.Radius,
State = state.State
};
return true;
}
private int AddPickup(in PickupSimData simData)
{
InitializeJobDataChannels();
return _pickups.Add(
new PickupIdentitySim { EntityId = simData.EntityId },
new PickupTransformSim { Position = ToFloat3(simData.Position) },
new PickupRadiusSim { Radius = simData.PickupRadius },
new PickupStateSim { State = simData.State });
}
internal int UpsertPickup(in PickupSimData simData)
{
if (!_pickups.TryGetSimulationIndex(simData.EntityId, out int index))
{
return AddPickup(in simData);
}
_pickups.Identity[index] = new PickupIdentitySim { EntityId = simData.EntityId };
_pickups.Transform[index] = new PickupTransformSim { Position = ToFloat3(simData.Position) };
_pickups.Radius[index] = new PickupRadiusSim { Radius = simData.PickupRadius };
_pickups.State[index] = new PickupStateSim { State = simData.State };
return index;
}
public void TriggerFullMapMagnet()
{
int pickupCount = _pickups.Count;
for (int i = 0; i < pickupCount; i++)
{
_pickups.State[i] = new PickupStateSim { State = PickupStateSim.StateAbsorbing };
}
}
private bool RemovePickupByEntityId(int entityId)
{
if (!PickupBinding.TryGetSimulationIndex(entityId, out int simulationIndex))
{
return false;
}
int lastIndex = _pickups.Count - 1;
if (simulationIndex != lastIndex)
{
PickupSimData movedData = _pickups[lastIndex];
_pickups[simulationIndex] = movedData;
PickupBinding.RemapIndex(movedData.EntityId, simulationIndex);
}
_pickups.RemoveAt(lastIndex);
PickupBinding.UnbindByEntityId(entityId);
return true;
return _pickups.RemoveByEntityId(entityId);
}
private void RegisterPickupLifecycle(EntityBase pickupEntity)