Inseln entfernen
Ich habe so etwas schon in einem meiner Spiele gemacht. Um die äußeren Inseln loszuwerden, war der Prozess im Grunde:
- Zunächst muss gewährleistet sein, dass das Zentrum der Karte immer zum Hauptland gehört und jedes Pixel entweder als "Land" oder "Wasser" (dh in verschiedenen Farben) beginnt.
- Dann fülle die Karte von der Mitte aus in vier Richtungen und verteile sie auf allen "Land" -Kacheln. Markieren Sie jedes Pixel, das von dieser Überflutungsfüllung besucht wird, als einen anderen Typ, z. B. "MainLand".
- Gehen Sie schließlich über die gesamte Karte und konvertieren Sie alle verbleibenden "Land" -Pixel in "Wasser", um andere Inseln zu entfernen.
Seen entfernen
Um die Löcher (oder Seen) auf der Insel zu beseitigen, gehen Sie ähnlich vor, beginnen jedoch an den Ecken der Karte und breiten sich stattdessen über die "Wasser" -Kacheln aus. Auf diese Weise können Sie das "Meer" von den anderen Wasserplättchen unterscheiden und Sie können sie dann genauso entfernen, wie Sie die Inseln zuvor beseitigt haben.
Beispiel
Lassen Sie mich meine Umsetzung der Flußfüllen ausgraben , dass ich hier irgendwo (Disclaimer, scherte ich nicht um Effizienz, also bin ich sicher , es gibt viele effizientere Wege zu ihrer Umsetzung):
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);
}
Ich habe dies als ersten Schritt benutzt, um die Seen in meinem Spiel loszuwerden. Nachdem ich das angerufen hatte, musste ich nur noch Folgendes tun:
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;
}
Bearbeiten
Hinzufügen einiger zusätzlicher Informationen basierend auf den Kommentaren. Falls Ihr Suchraum zu groß ist, kann es bei Verwendung der rekursiven Version des Algorithmus zu einem Stapelüberlauf kommen. Hier ist ein Link zum Stackoverflow (Wortspiel beabsichtigt :-)) zu einer nicht rekursiven Version des Algorithmus. Verwenden Sie Stack<T>
stattdessen einen (auch in C #, um meiner Antwort zu entsprechen), der sich leicht an andere Sprachen anpassen lässt, und es gibt andere Implementierungen dazu Link auch).