Код: Выделить всё
private List GenerateRandomPositions()
{
// Poisson Disc Sampling on a toroidal (seamless) domain
float cellSize = _spacing / Mathf.Sqrt2;
int width = Mathf.CeilToInt(_areaSize.X / cellSize);
int height = Mathf.CeilToInt(_areaSize.Y / cellSize);
int[,] cells = new int[width, height];
List positions = new List();
List frontierPositions = new List();
// Seed algorithm at center
Vector2 seed = _halfAreaSize;
frontierPositions.Add(seed);
positions.Add(seed);
cells[(int)(seed.X / cellSize), (int)(seed.Y / cellSize)] = 1;
// Start position generation loop
while (frontierPositions.Count > 0)
{
int spawnIndex = (int)(GD.Randf() * frontierPositions.Count);
Vector2 spawnCenter = frontierPositions[spawnIndex];
bool candidateAccepted = false;
for (int i = 0; i < _samplesBeforeRejection; i++) // Try _sampleBeforeRejection times to find a valid candidate
{
float angle = GD.Randf() * Mathf.Tau;
Vector2 direction = new Vector2(Mathf.Sin(angle), Mathf.Cos(angle));
Vector2 candidatePosition = spawnCenter + direction * (float)GD.RandRange(_spacing, _spacing * 2);
// wrap candidate into tile
candidatePosition.X = (candidatePosition.X % _areaSize.X + _areaSize.X) % _areaSize.X;
candidatePosition.Y = (candidatePosition.Y % _areaSize.Y + _areaSize.Y) % _areaSize.Y;
if (IsValid(candidatePosition)) // Accept candidate if it's valid
{
positions.Add(candidatePosition);
frontierPositions.Add(candidatePosition);
int cx = (int)(candidatePosition.X / cellSize) % width;
int cy = (int)(candidatePosition.Y / cellSize) % height;
cells[cx, cy] = positions.Count;
candidateAccepted = true;
break;
}
}
if (!candidateAccepted) // Remove candidate if it is not valid
frontierPositions.RemoveAt(spawnIndex);
}
// center around origin
for (int i = 0; i < positions.Count; i++)
positions[i] -= _halfAreaSize;
return positions;
bool IsValid(Vector2 candidatePosition)
{
// assume candidate already wrapped
int cellX = (int)(candidatePosition.X / cellSize) % width;
int cellY = (int)(candidatePosition.Y / cellSize) % height;
int startX = cellX - 2;
int endX = cellX + 2;
int startY = cellY - 2;
int endY = cellY + 2;
for (int x = startX; x _areaSize.Y * 0.5f) dy = _areaSize.Y - dy;
float toroidalDistance = dx * dx + dy * dy;
if (toroidalDistance < _spacing * _spacing)
return false;
}
}
}
return true;
}
}
Подробнее здесь: https://stackoverflow.com/questions/795 ... rithm-fine