Checkpoint 2 & Checkpoint 3

Checkpoint 2:Simulation 与 Job 数据通道打通
- 新增 Job 数据通道(Persistent NativeList)与 Simulation <-> NativeContainer 拷贝/回写流程
- 在生命周期接入通道管理(初始化、清空、集中释放)并接入 UseJobSimulation 分支
- 增强通道健壮性:失效容器自动重建,避免 EditMode 下 ObjectDisposedException
- 增加 UseJobSimulation 分支回归用例(EditMode/PlayMode 各 1 条)

Checkpoint 3:敌人移动与朝向 Job 化
- UseJobSimulation 分支正式切到 Job 路径
- 新增敌人移动/朝向 Job 实现(IJobParallelFor):
	- Burst 版本 + 非 Burst 版本(受 UseBurstJobs 开关控制)
	- Job 计算移动、朝向、状态;主线程补做分离避让回补
- 扩展数据通道能力(为 Job 输出缓冲和投射物输出同步提供接口)
- 补充分支回归测试(开启 UseJobSimulation 后验证追踪与朝向)
This commit is contained in:
SepComet
2026-02-22 10:47:42 +08:00
parent 76ed9a3e53
commit 34b1424bb6
8 changed files with 663 additions and 6 deletions
@@ -38,6 +38,9 @@ namespace Simulation.Tests.Editor
private static readonly MethodInfo SetUseSimulationMovementMethod =
SimulationWorldType?.GetMethod("SetUseSimulationMovement", PublicInstance);
private static readonly MethodInfo SetUseJobSimulationMethod =
SimulationWorldType?.GetMethod("SetUseJobSimulation", PublicInstance);
private static readonly MethodInfo UseGridBucketSolverMethod =
EnemySeparationSolverProviderType?.GetMethod("UseGridBucketSolver", PublicStatic);
@@ -65,6 +68,7 @@ namespace Simulation.Tests.Editor
Assert.NotNull(TryGetEnemyDataMethod, "TryGetEnemyData reflection lookup failed.");
Assert.NotNull(TickMethod, "Tick reflection lookup failed.");
Assert.NotNull(SetUseSimulationMovementMethod, "SetUseSimulationMovement reflection lookup failed.");
Assert.NotNull(SetUseJobSimulationMethod, "SetUseJobSimulation reflection lookup failed.");
Assert.NotNull(UseGridBucketSolverMethod, "UseGridBucketSolver reflection lookup failed.");
Assert.NotNull(EnemiesProperty, "Enemies property reflection lookup failed.");
@@ -143,6 +147,23 @@ namespace Simulation.Tests.Editor
Assert.That((int)GetField(GetEnemyAt(1), "EntityId"), Is.EqualTo(2003));
}
[Test]
public void TickEnemies_ChasesPlayer_WhenJobSimulationChannelEnabled()
{
SetUseJobSimulationMethod.Invoke(_worldComponent, new object[] { true });
UpsertEnemy(CreateEnemy(entityId: 1101, position: Vector3.zero, speed: 2f, attackRange: 1f));
InvokeTick(deltaTime: 1f, realDeltaTime: 1f, playerPosition: new Vector3(10f, 0f, 0f));
object enemy = GetEnemyAt(0);
Assert.That((int)GetField(enemy, "State"), Is.EqualTo(1));
Vector3 position = (Vector3)GetField(enemy, "Position");
Vector3 forward = (Vector3)GetField(enemy, "Forward");
Assert.That(position.x, Is.EqualTo(2f).Within(0.0001f));
Assert.That(position.z, Is.EqualTo(0f).Within(0.0001f));
Assert.That(forward.x, Is.EqualTo(1f).Within(0.0001f));
}
private object CreateEnemy(int entityId, Vector3 position, float speed, float attackRange)
{
object enemy = System.Activator.CreateInstance(EnemySimDataType);