Untitled
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