Видалення островів
Я робив подібні речі раніше в одній зі своїх ігор. Щоб позбутися від зовнішніх островів, процес був в основному:
- По-перше, має бути гарантія, що центр карти завжди буде належати основній землі, і кожен піксель починається як "Земля", або "Вода" (тобто різних кольорів).
- Потім зробіть заливку в чотири напрямки, починаючи від центральної карти і розкладаючи по всій плитці "Земля". Позначте кожен піксель, відвіданий цією заливкою, як інший тип, наприклад, "MainLand".
- Нарешті перейдіть по всій карті та перетворіть будь-який залишився піксель "Суша" у "Вода, щоб позбутися інших островів.
Видалення озер
Що стосується позбавлення від дір (або озер) всередині острова, ви робите подібний процес, але починаючи з кутів карти та натомість поширюючи плитки "Вода". Це дозволить вам відрізнити «Море» від інших водних плиток, і тоді ви зможете позбутися від них так само, як ви позбулися островів раніше.
Приклад
Дозвольте мені розкопати мою реалізацію заливного потоку, який у мене є десь (відмова, я не піклувався про ефективність, тому я впевнений, що існує багато більш ефективних способів його реалізації):
private void GenerateSea()
{
// Initialize visited tiles list
visited.Clear();
// Start generating sea from the four corners
GenerateSeaRecursive(new Point(0, 0));
GenerateSeaRecursive(new Point(size.Width - 1, 0));
GenerateSeaRecursive(new Point(0, size.Height - 1));
GenerateSeaRecursive(new Point(size.Width - 1, size.Height - 1));
}
private void GenerateSeaRecursive(Point point)
{
// End recursion if point is outside bounds
if (!WithinBounds(point)) return;
// End recursion if the current spot is a land
if (tiles[point.X, point.Y].Land) return;
// End recursion if this spot has already been visited
if (visited.Contains(point)) return;
// Add point to visited points list
visited.Add(point);
// Calculate neighboring tiles coordinates
Point right = new Point(point.X + 1, point.Y);
Point left = new Point(point.X - 1, point.Y);
Point up = new Point(point.X, point.Y - 1);
Point down = new Point(point.X, point.Y + 1);
// Mark neighbouring tiles as Sea if they're not Land
if (WithinBounds(right) && tiles[right.X, right.Y].Empty)
tiles[right.X, right.Y].Sea = true;
if (WithinBounds(left) && tiles[left.X, left.Y].Empty)
tiles[left.X, left.Y].Sea = true;
if (WithinBounds(up) && tiles[up.X, up.Y].Empty)
tiles[up.X, up.Y].Sea = true;
if (WithinBounds(down) && tiles[down.X, down.Y].Empty)
tiles[down.X, down.Y].Sea = true;
// Call the function recursively for the neighboring tiles
GenerateSeaRecursive(right);
GenerateSeaRecursive(left);
GenerateSeaRecursive(up);
GenerateSeaRecursive(down);
}
Я використовував це як перший крок, щоб позбутися озер у своїй грі. Після зателефонувавши до цього, все, що мені потрібно було б зробити, було щось на кшталт:
private void RemoveLakes()
{
// Now that sea is generated, any empty tile should be removed
for (int j = 0; j != size.Height; j++)
for (int i = 0; i != size.Width; i++)
if (tiles[i, j].Empty) tiles[i, j].Land = true;
}
Редагувати
Додавання додаткової інформації на основі коментарів. Якщо ваш пошуковий простір занадто великий, ви можете відчути переповнення стека при використанні рекурсивної версії алгоритму. Ось посилання на stackoverflow (каламбур призначений :-)) на не рекурсивну версію алгоритму, використовуючи Stack<T>
натомість (також у C #, щоб відповідати моїй відповіді, але слід легко адаптуватись до інших мов, і на цьому є інші реалізації. посилання теж).