Untitled

mail@pastecode.io avatar
unknown
plain_text
5 months ago
5.0 kB
2
Indexable
using System;
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;

namespace Game.World.Views.Spreads.Jobs
{
    [BurstCompile]
    public struct CreateGradationMapJob : IJob
    {
        public NativeArray<int> GradationMap;
        public int Gradations;
        public int Width;
        public int Height;

        public NativeList<int> PointQueue;
        public NativeArray<bool> Filled;

        private int _pixelsCount;
        private int _remaining;
        private int _filledCount;
        private int _colorId;
        private int _currentGradation;
        private int _pixelsPerColor;

        public void Execute()
        {
            Unity.Mathematics.Random random = new Unity.Mathematics.Random((uint)Environment.TickCount);

            _pixelsCount = Width * Height;
            _pixelsPerColor = _pixelsCount / Gradations;
            int expectedCount = _pixelsPerColor * Gradations;
            _filledCount = 0;
            _remaining = 0;
            _colorId = -1;

            // Ініціалізуємо заповнення для кожного кольору
            for (int i = 0; i < Gradations; i++)
            {
                int currentX = random.NextInt(0, Width);
                int currentY = random.NextInt(0, Height);
                _currentGradation = i;

                FillCircle(currentX, currentY, i);
            }

            // Продовжуємо заповнювати поки не заповнимо очікувану кількість пікселів
            while (_filledCount < expectedCount)
            {
                if (PointQueue.Length > 0)
                {
                    int currentPoint = PointQueue[0];
                    PointQueue.RemoveAtSwapBack(0);

                    int x = currentPoint % Width;
                    int y = currentPoint / Width;
                    TryFillCircle(x, y);
                }
                else
                {
                    break;
                }
            }
        }

        private void FillCircle(int startX, int startY, int gradation)
        {
            PointQueue.Clear();
            PointQueue.Add(startX + startY * Width);
            SetFilledValue(startX, startY, true);
            GradationMap[startX + startY * Width] = gradation;
            _filledCount++;
            _remaining = _pixelsPerColor - 1; // Мінус один, бо початкова точка вже заповнена

            int radius = 1;

            while (_remaining > 0 && PointQueue.Length > 0)
            {
                int currentPoint = PointQueue[0];
                PointQueue.RemoveAtSwapBack(0);

                int x = currentPoint % Width;
                int y = currentPoint / Width;

                for (int dx = -radius; dx <= radius; dx++)
                {
                    for (int dy = -radius; dy <= radius; dy++)
                    {
                        if (dx * dx + dy * dy <= radius * radius)
                        {
                            Fill(x + dx, y + dy);
                        }
                    }
                }

                radius++;
            }
        }

        private void TryFillCircle(int x, int y)
        {
            int radius = 1;

            while (_remaining > 0 && _filledCount < _pixelsCount)
            {
                for (int dx = -radius; dx <= radius; dx++)
                {
                    for (int dy = -radius; dy <= radius; dy++)
                    {
                        if (dx * dx + dy * dy <= radius * radius)
                        {
                            Fill(x + dx, y + dy);
                        }
                    }
                }
                radius++;
            }
        }

        private void Fill(int x, int y)
        {
            if (x < 0 || x >= Width || y < 0 || y >= Height || GetFilledValue(x, y))
            {
                return;
            }

            if (_remaining == 0)
            {
                return;
            }

            int index = x + y * Width;
            PointQueue.Add(index);
            SetFilledValue(x, y, true);
            _filledCount++;
            GradationMap[index] = _currentGradation;
            _remaining--;
        }

        private bool GetFilledValue(int x, int y)
        {
            if (x < 0 || x >= Width || y < 0 || y >= Height)
            {
                throw new ArgumentOutOfRangeException("Error 0");
            }
            int index = y * Width + x;
            bool result = Filled[index];
            return result;
        }

        private void SetFilledValue(int x, int y, bool value)
        {
            if (x < 0 || x >= Width || y < 0 || y >= Height)
            {
                throw new ArgumentOutOfRangeException("Error 1");
            }
            int index = y * Width + x;
            Filled[index] = value;
        }
    }
}
Leave a Comment