Rimozione di isole
Ho già fatto questo genere di cose in uno dei miei giochi. Per sbarazzarsi delle isole esterne, il processo era sostanzialmente:
- Innanzitutto deve esserci una garanzia che il centro della mappa apparterrà sempre alla terra principale e ogni pixel inizia come "Terra" o "Acqua" (ovvero colori diversi).
- Quindi esegui un riempimento in quattro direzioni iniziando dal centro della mappa e diffondendosi su tutte le tessere "Terra". Contrassegna ogni pixel visitato da questo riempimento di tipo flood come un tipo diverso come "MainLand".
- Infine, passa su tutta la mappa e converti i pixel "Terra" rimanenti in "Acqua per sbarazzarti di altre isole.
Rimozione dei laghi
Per quanto riguarda la rimozione dei buchi (o dei laghi) all'interno dell'isola, fai un processo simile ma partendo dagli angoli della mappa e diffondendo invece le tessere "Acqua". Questo ti permetterà di distinguere il "Mare" dalle altre tessere d'acqua, e quindi puoi sbarazzartene proprio come ti sei sbarazzato delle isole prima.
Esempio
Consentitemi di approfondire la mia implementazione dell'inondazione che ho qui da qualche parte (dichiarazione di non responsabilità, non mi importava dell'efficienza, quindi sono sicuro che ci sono molti modi più efficienti per implementarlo):
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);
}
Ho usato questo come primo passo per sbarazzarmi dei laghi nel mio gioco. Dopo averlo chiamato, tutto ciò che dovevo fare era qualcosa del tipo:
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;
}
modificare
Aggiunta di alcune informazioni aggiuntive in base ai commenti. Nel caso in cui lo spazio di ricerca sia troppo grande, è possibile che si verifichi un overflow dello stack quando si utilizza la versione ricorsiva dell'algoritmo. Ecco un link su StackOverflow (gioco di parole :-)) a una versione non ricorsiva dell'algoritmo, usando Stack<T>
invece (anche in C # per abbinare la mia risposta, ma dovrebbe essere facile adattarsi ad altre lingue, e ci sono altre implementazioni su questo anche link).