100 lines
3.8 KiB
C#
100 lines
3.8 KiB
C#
using Unity.Burst;
|
|
using Unity.Collections;
|
|
using Unity.Jobs;
|
|
using Unity.Mathematics;
|
|
|
|
namespace SepCore.Simulation
|
|
{
|
|
internal static class PickupMovementSystem
|
|
{
|
|
// 读写集:R/W PickupTransform / PickupState; R PickupIdentity / PickupRadius
|
|
// W CollectedPickups
|
|
public static JobHandle Schedule(PickupStore pickups, NativeList<int> collectedPickups,
|
|
float deltaTime, float3 playerPosition, float absorbRange, float absorbSpeed, float collectDistance,
|
|
JobHandle dependency)
|
|
{
|
|
int pickupCount = pickups.Count;
|
|
if (pickupCount == 0)
|
|
{
|
|
return dependency;
|
|
}
|
|
|
|
PickupMovementJob job = new PickupMovementJob
|
|
{
|
|
Transforms = pickups.Transform.Data.AsArray(),
|
|
States = pickups.State.Data.AsArray(),
|
|
Identities = pickups.Identity.Data.AsArray(),
|
|
Radii = pickups.Radius.Data.AsArray(),
|
|
CollectedPickups = collectedPickups.AsParallelWriter(),
|
|
PlayerPosition = playerPosition,
|
|
AbsorbRange = math.max(0f, absorbRange),
|
|
AbsorbSpeed = math.max(0f, absorbSpeed),
|
|
CollectDistance = math.max(0f, collectDistance),
|
|
DeltaTime = deltaTime
|
|
};
|
|
return job.Schedule(pickupCount, 64, dependency);
|
|
}
|
|
}
|
|
|
|
[BurstCompile]
|
|
internal struct PickupMovementJob : IJobParallelFor
|
|
{
|
|
public NativeArray<PickupTransformSim> Transforms;
|
|
public NativeArray<PickupStateSim> States;
|
|
[ReadOnly] public NativeArray<PickupIdentitySim> Identities;
|
|
[ReadOnly] public NativeArray<PickupRadiusSim> Radii;
|
|
public NativeList<int>.ParallelWriter CollectedPickups;
|
|
public float3 PlayerPosition;
|
|
public float AbsorbRange;
|
|
public float AbsorbSpeed;
|
|
public float CollectDistance;
|
|
public float DeltaTime;
|
|
|
|
public void Execute(int index)
|
|
{
|
|
PickupTransformSim transform = Transforms[index];
|
|
PickupStateSim state = States[index];
|
|
PickupIdentitySim identity = Identities[index];
|
|
PickupRadiusSim radius = Radii[index];
|
|
|
|
float3 currentPosition = transform.Position;
|
|
float3 horizontalPosition = new float3(currentPosition.x, 0f, currentPosition.z);
|
|
float3 toPlayer = PlayerPosition - horizontalPosition;
|
|
float sqrDistance = math.lengthsq(toPlayer);
|
|
|
|
float effectiveCollectDistance = math.max(CollectDistance, radius.Radius);
|
|
float sqrCollectDistance = effectiveCollectDistance * effectiveCollectDistance;
|
|
|
|
if (sqrDistance <= sqrCollectDistance)
|
|
{
|
|
CollectedPickups.AddNoResize(identity.EntityId);
|
|
return;
|
|
}
|
|
|
|
bool isAbsorbing = state.State == PickupStateSim.StateAbsorbing;
|
|
bool shouldAbsorb = isAbsorbing || (AbsorbRange > 0f && sqrDistance <= AbsorbRange * AbsorbRange);
|
|
|
|
if (shouldAbsorb && AbsorbSpeed > 0f && sqrDistance > float.Epsilon)
|
|
{
|
|
state.State = PickupStateSim.StateAbsorbing;
|
|
float distance = math.sqrt(sqrDistance);
|
|
float step = AbsorbSpeed * DeltaTime;
|
|
|
|
if (step >= distance)
|
|
{
|
|
transform.Position = new float3(PlayerPosition.x, currentPosition.y, PlayerPosition.z);
|
|
CollectedPickups.AddNoResize(identity.EntityId);
|
|
}
|
|
else
|
|
{
|
|
float3 direction = toPlayer / distance;
|
|
transform.Position = currentPosition + direction * step;
|
|
}
|
|
|
|
Transforms[index] = transform;
|
|
States[index] = state;
|
|
}
|
|
}
|
|
}
|
|
}
|