Files

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;
}
}
}