Protfolio-Emanuel-Polsky / Assets / _Project / Code / PathFinding / Systems / UpdateSpecificPointSystem.cs
UpdateSpecificPointSystem.cs
Raw
using GarmentButton.FlatenArray;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;


namespace GarmentButton.PathFinding
{
    [BurstCompile]
    public partial struct UpdateSpecificPointSystem : ISystem
    {
        private const int UPDATE_RADIUS = 5;

        [BurstCompile]
        public void OnCreate(ref SystemState state)
        {
            state.RequireForUpdate<GridData>();
            state.RequireForUpdate<GridAdditionalData>();
            state.RequireForUpdate<RequireUpdatePosition>();
        }

        [BurstCompile]
        public void OnUpdate(ref SystemState state)
        {
            var grid = SystemAPI.GetSingleton<GridData>();
            var entityGrid = SystemAPI.GetSingletonEntity<GridData>();
            if (SystemAPI.HasComponent<UpdatePoints>(entityGrid) || SystemAPI.HasComponent<CastTag>(entityGrid) ||
                SystemAPI.HasComponent<UpdateCheck>(entityGrid))
                return;

            var ecb = new EntityCommandBuffer(Allocator.Temp);
            var converter = new FlatenFloatArray2D(grid.GridSize, grid.CellSize, grid.Center);
            var gridLength = grid.GridSize.x * grid.GridSize.y;
            var initialCapacity = gridLength < 256 ? gridLength : 256;
            var visited = new NativeArray<byte>(gridLength, Allocator.Temp, NativeArrayOptions.ClearMemory);
            var addedPoints = new NativeList<ushort>(initialCapacity, Allocator.Temp);
            var currentPoints = new NativeList<int>(initialCapacity, Allocator.Temp);
            var nextPoints = new NativeList<int>(initialCapacity, Allocator.Temp);
            foreach (var (updatePosition, entity) in SystemAPI.Query<RefRO<RequireUpdatePosition>>().WithEntityAccess())
            {
                var starIndex = converter.GetCellAtPosition(updatePosition.ValueRO.Value);
                currentPoints.Clear();
                nextPoints.Clear();
                if (TryAddPoint(starIndex, visited, ref addedPoints))
                    currentPoints.Add(starIndex);

                for (var radius = 0; radius < UPDATE_RADIUS; radius++)
                {
                    for (var i = 0; i < currentPoints.Length; i++)
                    {
                        AddNeighbours(currentPoints[i], grid.GridSize.x, grid.GridSize.y, visited, ref addedPoints,
                            ref nextPoints);

                    }

                    var tempPoints = currentPoints;
                    currentPoints = nextPoints;
                    nextPoints = tempPoints;
                    nextPoints.Clear();
                }
                ecb.RemoveComponent<RequireUpdatePosition>(entity);
            }

            if (addedPoints.Length > 0)
            {
                ecb.AddComponent(entityGrid, new UpdatePoints
                {
                    Indexes = new NativeArray<ushort>(addedPoints.AsArray(), Allocator.Persistent)
                });
                ecb.AddComponent<CastTag>(entityGrid);
            }

            ecb.Playback(state.EntityManager);
            ecb.Dispose();
            visited.Dispose();
            currentPoints.Dispose();
            nextPoints.Dispose();
            addedPoints.Dispose();
        }

        private bool TryAddPoint(int index, NativeArray<byte> visited, ref NativeList<ushort> addedPoints)
        {
            if (visited[index] != 0)
                return false;

            visited[index] = 1;
            addedPoints.Add((ushort)index);
            return true;
        }

        private void AddNeighbours(int currentNodeIndex, int width, int height, NativeArray<byte> visited,
            ref NativeList<ushort> addedPoints, ref NativeList<int> nextPoints)
        {
            var pointX = currentNodeIndex % width;
            var pointY = currentNodeIndex / width;
            for (var yOffset = -1; yOffset <= 1; yOffset++)
            {
                for (var xOffset = -1; xOffset <= 1; xOffset++)
                {
                    if ((xOffset | yOffset) == 0)
                        continue;

                    var neighbourX = pointX + xOffset;
                    var neighbourY = pointY + yOffset;
                    if ((uint)neighbourX >= (uint)width || (uint)neighbourY >= (uint)height)
                        continue;

                    var neighbourIndex = neighbourY * width + neighbourX;
                    if (!TryAddPoint(neighbourIndex, visited, ref addedPoints))
                        continue;

                    nextPoints.Add(neighbourIndex);
                }
            }
        }
    }
}