In meinem Spiel habe ich eine Reihe von Kacheln in einem 2D-Array platziert, die durch ihre Xs und Zs ([1,1], [1,2] usw.) gekennzeichnet sind.
Jetzt möchte ich eine Art "Farbeimer" -Mechanismus: Wenn Sie eine Kachel auswählen, werden alle benachbarten Kacheln zerstört, bis eine Bedingung sie stoppt, sagen wir, wenn sie ein Objekt mit trifft hasFlag
.
Folgendes habe ich bisher, ich bin sicher, es ist ziemlich schlimm, es friert manchmal auch alles ein:
void destroyAdjacentTiles(int x, int z) {
int GridSize = Cubes.GetLength(0);
int minX = x == 0 ? x : x-1;
int maxX = x == GridSize - 1 ? x : x+1;
int minZ = z == 0 ? z : z-1;
int maxZ = z == GridSize - 1 ? z : z+1;
Debug.Log(string.Format("Cube: {0}, {1}; X {2}-{3}; Z {4}-{5}", x, z, minX, maxX, minZ, maxZ));
for (int curX = minX; curX <= maxX; curX++) {
for (int curZ = minZ; curZ <= maxZ; curZ++) {
if (Cubes[curX, curZ] != Cubes[x, z]) {
Debug.Log(string.Format(" Checking: {0}, {1}", curX, curZ));
if (Cubes[curX,curZ] && Cubes[curX,curZ].GetComponent<CubeBehavior>().hasFlag) {
Destroy(Cubes[curX,curZ]);
destroyAdjacentTiles(curX, curZ);
}
}
}
}
}
Update: Ich versuche die rekursive Version des Flood-Fill-Algorithmus, habe aber Probleme. Um das westlich angrenzende Plättchen zu überprüfen, verwende ich x-1, für den Osten x + 1 usw. Das Problem ist, sobald x = 0, wird es eine Endlosschleife zwischen 0 und 1 geben. Ich muss das auch überprüfen Kachel existiert, also benutze ich if
s, um es herauszufinden, um keine zu bekommen IndexOutOfRangeException
(ich habe versucht, try / catch zu verwenden, aber es ist so ziemlich das gleiche Ergebnis, ich dachte, das wäre einfacher). Hier ist mein Code (ja, ich reproduziere meinenSweeper):
bool destroyAdjacentTiles(int x, int z) {
int GridSize = Cubes.GetLength(0);
int minX = x == 0 ? x : x-1;
int maxX = x == GridSize - 1 ? x : x+1;
int minZ = z == 0 ? z : z-1;
int maxZ = z == GridSize - 1 ? z : z+1;
Debug.Log(string.Format("Cube: {0}, {1}; X {2}-{3}; Z {4}-{5}", x, z, minX, maxX, minZ, maxZ));
CubeBehavior thisCube = Cubes[x, z].GetComponent<CubeBehavior>();
if (thisCube.isMine) { Destroy(thisCube); Cubes[x,z] = null; return false; } // TO DO: Make this = game over
// BELOW: Always, no matter what, causes the object to destroy, dunno why. So I removed it for the time being.
//if (thisCube.surroundingMines >= 1) Destroy(thisCube); return true;
// if the function doesn't return by now, means it's a to-be-destroyed cube, so destroy it
//Destroy(thisCube.gameObject);
//Cubes[x,z] = null;
//
if (x > 0) {
if (Cubes[x-1,z].gameObject) destroyAdjacentTiles(x-1, z);
if (x < GridSize - 1)
if (Cubes[x+1,z].gameObject) destroyAdjacentTiles(x+1, z);
}
if (z > 0) {
if (Cubes[x,z-1].gameObject) destroyAdjacentTiles(x, z-1);
if (z < GridSize - 1)
if (Cubes[x,z+1].gameObject) destroyAdjacentTiles(x, z+1);
}
return true;
}
In solchen Fällen möchten Sie versuchen, rekursive Algorithmen zu vermeiden. Es ist besser, stapel- / warteschlangenbasierte Methoden zu verwenden, da diese schneller sind und keine Stapelüberläufe für große Bereiche verursachen. Diese Seite enthält Details und Quellenbeispiele für rekursive und stapelbasierte Flood-Fill-Algorithmen sowie Vergleiche der Ausführungsgeschwindigkeit: http://lodev.org/cgtutor/floodfill.html
quelle