Files
vampire-like/Assets/GameMain/Scripts/Runtime/CustomComponent/Simulation/Systems/PickupMovementSystem.cs
T

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