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(); state.RequireForUpdate(); state.RequireForUpdate(); state.RequireForUpdate(); } [BurstCompile] public void OnUpdate(ref SystemState state) { var grid = SystemAPI.GetSingleton(); var gridData = SystemAPI.GetSingleton(); var gridAdditional = SystemAPI.GetSingleton().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 Grid; [ReadOnly] public FlatenFloatArray2D Converter; [ReadOnly] public NativeArray.ReadOnly GroundTypes; [ReadOnly] public float TimeDelta; public void Execute(ref DynamicBuffer buffer, ref LastPointPath lastPoint, EnabledRefRW 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; } } }