Protfolio-Emanuel-Polsky / Assets / _Project / Code / PathFinding / Systems / UpdatePathBufferBasePosition.cs
UpdatePathBufferBasePosition.cs
Raw
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;
        }
    }
}