95 lines
3.4 KiB
C#
95 lines
3.4 KiB
C#
using Unity.Burst;
|
||
using Unity.Collections;
|
||
using Unity.Jobs;
|
||
using Unity.Mathematics;
|
||
|
||
namespace SepCore.Simulation
|
||
{
|
||
internal static class EnemyMovementSystem
|
||
{
|
||
// 读写集:R EnemyTransform / EnemyMoveInput / EnemyAttack;W EnemyTransform / EnemyBehavior
|
||
public static JobHandle Schedule(EnemyStore enemies, float deltaTime, float3 playerPosition,
|
||
JobHandle dependency)
|
||
{
|
||
int enemyCount = enemies.Count;
|
||
if (enemyCount == 0)
|
||
{
|
||
return dependency;
|
||
}
|
||
|
||
EnemyMovementJob job = new EnemyMovementJob
|
||
{
|
||
Transforms = enemies.Transform.Data.AsArray(),
|
||
MoveInputs = enemies.MoveInput.Data.AsArray(),
|
||
Attacks = enemies.Attack.Data.AsArray(),
|
||
Behaviors = enemies.Behavior.Data.AsArray(),
|
||
DeltaTime = deltaTime,
|
||
PlayerPosition = playerPosition
|
||
};
|
||
return job.Schedule(enemyCount, 64, dependency);
|
||
}
|
||
}
|
||
|
||
[BurstCompile]
|
||
internal struct EnemyMovementJob : IJobParallelFor
|
||
{
|
||
public NativeArray<EnemyTransformSim> Transforms;
|
||
[ReadOnly] public NativeArray<EnemyMoveInputSim> MoveInputs;
|
||
[ReadOnly] public NativeArray<EnemyAttackSim> Attacks;
|
||
public NativeArray<EnemyBehaviorSim> Behaviors;
|
||
public float DeltaTime;
|
||
public float3 PlayerPosition;
|
||
|
||
public void Execute(int index)
|
||
{
|
||
EnemyMoveInputSim moveInput = MoveInputs[index];
|
||
EnemyAttackSim attack = Attacks[index];
|
||
EnemyTransformSim transform = Transforms[index];
|
||
|
||
float attackRange = attack.AttackRange > 0f ? attack.AttackRange : EnemyAttackSim.DefaultAttackRange;
|
||
float attackRangeSqr = attackRange * attackRange;
|
||
|
||
float3 currentPosition = transform.Position;
|
||
float3 horizontalPosition = new float3(currentPosition.x, 0f, currentPosition.z);
|
||
float3 toPlayer = PlayerPosition - horizontalPosition;
|
||
float sqrDistance = math.lengthsq(toPlayer);
|
||
bool isInAttackRange = sqrDistance <= attackRangeSqr;
|
||
bool canChase = !isInAttackRange && moveInput.Speed > 0f && sqrDistance > float.Epsilon;
|
||
|
||
float3 forward = transform.Forward;
|
||
float3 desiredPosition = currentPosition;
|
||
quaternion rotation = transform.Rotation;
|
||
|
||
if (canChase)
|
||
{
|
||
forward = math.normalizesafe(toPlayer, forward);
|
||
desiredPosition = currentPosition + forward * moveInput.Speed * DeltaTime;
|
||
if (math.lengthsq(forward) > float.Epsilon)
|
||
{
|
||
rotation = quaternion.LookRotationSafe(forward, math.up());
|
||
}
|
||
}
|
||
|
||
int nextState;
|
||
if (isInAttackRange)
|
||
{
|
||
nextState = EnemyBehaviorSim.StateInAttackRange;
|
||
}
|
||
else if (canChase)
|
||
{
|
||
nextState = EnemyBehaviorSim.StateChasing;
|
||
}
|
||
else
|
||
{
|
||
nextState = EnemyBehaviorSim.StateIdle;
|
||
}
|
||
|
||
transform.Position = desiredPosition;
|
||
transform.Forward = forward;
|
||
transform.Rotation = rotation;
|
||
Transforms[index] = transform;
|
||
Behaviors[index] = new EnemyBehaviorSim { State = nextState };
|
||
}
|
||
}
|
||
}
|