88 lines
3.3 KiB
C#
88 lines
3.3 KiB
C#
using Unity.Burst;
|
|
using Unity.Collections;
|
|
using Unity.Jobs;
|
|
using Unity.Mathematics;
|
|
|
|
namespace SepCore.Simulation
|
|
{
|
|
internal static class ProjectileMovementSystem
|
|
{
|
|
// 读写集:R/W ProjectileTransform / ProjectileVelocity / ProjectileLife
|
|
public static JobHandle Schedule(ProjectileStore projectiles, float deltaTime, float3 playerPosition,
|
|
float maxDistanceFromPlayer, float maxVerticalOffsetFromPlayer, JobHandle dependency)
|
|
{
|
|
int projectileCount = projectiles.Count;
|
|
if (projectileCount == 0)
|
|
{
|
|
return dependency;
|
|
}
|
|
|
|
float maxDistance = math.max(0f, maxDistanceFromPlayer);
|
|
float maxSqrDistanceFromPlayer = maxDistance > 0f ? maxDistance * maxDistance : -1f;
|
|
float maxVerticalOffset = math.max(0f, maxVerticalOffsetFromPlayer);
|
|
|
|
ProjectileMovementJob job = new ProjectileMovementJob
|
|
{
|
|
Transforms = projectiles.Transform.Data.AsArray(),
|
|
Velocities = projectiles.Velocity.Data.AsArray(),
|
|
Lives = projectiles.Life.Data.AsArray(),
|
|
DeltaTime = deltaTime,
|
|
PlayerPosition = playerPosition,
|
|
MaxSqrDistanceFromPlayer = maxSqrDistanceFromPlayer,
|
|
MaxVerticalOffsetFromPlayer = maxVerticalOffset
|
|
};
|
|
return job.Schedule(projectileCount, 64, dependency);
|
|
}
|
|
}
|
|
|
|
[BurstCompile]
|
|
internal struct ProjectileMovementJob : IJobParallelFor
|
|
{
|
|
public NativeArray<ProjectileTransformSim> Transforms;
|
|
public NativeArray<ProjectileVelocitySim> Velocities;
|
|
public NativeArray<ProjectileLifeSim> Lives;
|
|
public float DeltaTime;
|
|
public float3 PlayerPosition;
|
|
public float MaxSqrDistanceFromPlayer;
|
|
public float MaxVerticalOffsetFromPlayer;
|
|
|
|
public void Execute(int index)
|
|
{
|
|
ProjectileLifeSim life = Lives[index];
|
|
if (!life.Active)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ProjectileTransformSim transform = Transforms[index];
|
|
float3 velocity = Velocities[index].Velocity;
|
|
float3 nextPosition = transform.Position + velocity * DeltaTime;
|
|
float nextAge = math.max(0f, life.Age + DeltaTime);
|
|
bool shouldExpire = life.LifeTime > 0f && nextAge >= life.LifeTime;
|
|
|
|
if (!shouldExpire && MaxSqrDistanceFromPlayer > 0f)
|
|
{
|
|
float3 horizontalDelta =
|
|
new float3(nextPosition.x - PlayerPosition.x, 0f, nextPosition.z - PlayerPosition.z);
|
|
shouldExpire = math.lengthsq(horizontalDelta) > MaxSqrDistanceFromPlayer;
|
|
}
|
|
|
|
if (!shouldExpire && MaxVerticalOffsetFromPlayer > 0f)
|
|
{
|
|
shouldExpire = math.abs(nextPosition.y - PlayerPosition.y) > MaxVerticalOffsetFromPlayer;
|
|
}
|
|
|
|
transform.Position = nextPosition;
|
|
if (math.lengthsq(velocity) > float.Epsilon)
|
|
{
|
|
transform.Forward = math.normalizesafe(velocity, transform.Forward);
|
|
}
|
|
|
|
Transforms[index] = transform;
|
|
life.Age = nextAge;
|
|
life.Active = !shouldExpire;
|
|
Lives[index] = life;
|
|
}
|
|
}
|
|
}
|