using GarmentButton.FlatenArray;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
namespace GarmentButton.PathFinding
{
[BurstCompile]
[UpdateAfter(typeof(CalculatePathSystem))]
public partial struct UpdatePathBufferBasePosition : ISystem
{
[BurstCompile]
public void OnCreate(ref SystemState state)
{
state.RequireForUpdate<GridAdditionalData>();
state.RequireForUpdate<Grid>();
state.RequireForUpdate<GridData>();
state.RequireForUpdate<PathElement>();
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
var grid = SystemAPI.GetSingleton<Grid>();
var gridData = SystemAPI.GetSingleton<GridData>();
var gridAdditional = SystemAPI.GetSingleton<GridAdditionalData>().Types;
var converter = new FlatenFloatArray2D(gridData.GridSize, gridData.CellSize, gridData.Center);
var time = SystemAPI.Time.DeltaTime;
state.Dependency = new UpdateGridPositionJob
{
Grid = grid.Value,
Converter = converter,
GroundTypes = gridAdditional.AsReadOnly(),
TimeDelta = time,
}.ScheduleParallel(state.Dependency);
}
[BurstCompile]
[WithOptions(EntityQueryOptions.IgnoreComponentEnabledState)]
public partial struct UpdateGridPositionJob : IJobEntity
{
private const float LIMIT_STUCK_TIME = 1.5f;
private const int TARGET_REACHED_DISTANCE = 15;
[ReadOnly] public BlobAssetReference<PointPathBlobAsset> Grid;
[ReadOnly] public FlatenFloatArray2D Converter;
[ReadOnly] public NativeArray<GroundType>.ReadOnly GroundTypes;
[ReadOnly] public float TimeDelta;
public void Execute(ref DynamicBuffer<PathElement> buffer, ref LastPointPath lastPoint,
EnabledRefRW<EndPointPath> endPoint, ref CheckStuck stuck, in LocalTransform transform)
{
if (buffer.Length <= 0)
return;
var characterIndex = Converter.GetCellAtPosition(transform.Position.xz);
var characterPosition = Grid.Value.Array[characterIndex];
var targetPosition = Grid.Value.Array[buffer[0].IndexGrid];
var distanceX = characterPosition.X - targetPosition.X;
var distanceZ = characterPosition.Z - targetPosition.Z;
var distanceSquared = distanceX * distanceX + distanceZ * distanceZ;
var isStuck = characterIndex == stuck.Index;
if (isStuck)
{
if (stuck.Time > LIMIT_STUCK_TIME)
{
endPoint.ValueRW = true;
stuck.Time = 0;
}
stuck.Time += TimeDelta;
}
else
{
stuck.Time = 0;
}
stuck.Index = characterIndex;
if (distanceSquared >= TARGET_REACHED_DISTANCE * TARGET_REACHED_DISTANCE)
return;
var targetHeight = (float)targetPosition.Y / 10;
var destinationGround = GroundTypes[buffer[0].IndexGrid];
if (!IsNextPlatformIsLower(targetHeight, transform.Position.y))
{
return;
}
var hasMorePointsAhead = buffer.Length > 1;
if (hasMorePointsAhead)
{
var nextGroundType = GroundTypes[buffer[1].IndexGrid];
var nearEdgeToJump = destinationGround == GroundType.NearGround && nextGroundType == GroundType.Air;
var isCloseToGround = IsCloseToGround(targetHeight, transform.Position.y, 0.5f);
if (nearEdgeToJump && !isCloseToGround)
return;
}
lastPoint.Value = buffer[0].IndexGrid;
buffer.RemoveAt(0);
}
private bool IsNextPlatformIsLower(float nextHeight, float currentHeight) =>
nextHeight <= currentHeight + 0.05f;
private bool IsCloseToGround(float nextHeight, float currentHeight, float distance) =>
math.abs(nextHeight - currentHeight) < distance;
}
}
}