การถอดหมู่เกาะ
ฉันเคยทำสิ่งนี้มาก่อนในเกมของฉัน เพื่อกำจัดเกาะรอบนอกกระบวนการเป็นพื้น:
- ก่อนอื่นจะต้องมีการรับประกันศูนย์กลางของแผนที่จะเป็นของที่ดินหลักเสมอและแต่ละพิกเซลจะเริ่มต้นเป็น "ที่ดิน" หรือ "น้ำ" (เช่นสีที่ต่างกัน)
- จากนั้นเติมน้ำท่วมสี่ทิศทางเริ่มต้นจากศูนย์กลางแผนที่และกระจายไปทั่วแผ่น "ที่ดิน" ทำเครื่องหมายทุกพิกเซลที่มีผู้เยี่ยมชมกรอกข้อมูลนี้เป็นประเภทอื่นเช่น "MainLand"
- ในที่สุดไปทั่วทั้งแผนที่และแปลงพิกเซล "Land" ที่เหลืออยู่เป็น "Water" เพื่อกำจัดเกาะอื่น ๆ
การถอด Lakes
สำหรับการกำจัดหลุม (หรือทะเลสาบ) ภายในเกาะคุณทำกระบวนการที่คล้ายกัน แต่เริ่มจากมุมของแผนที่และแพร่กระจายผ่านแผ่น "น้ำ" แทน สิ่งนี้จะช่วยให้คุณแยก "ทะเล" ออกจากแผ่นน้ำอื่น ๆ และจากนั้นคุณสามารถกำจัดมันได้เหมือนกับที่คุณกำจัดเกาะมาก่อน
ตัวอย่าง
ผมขอขุดขึ้นมาการดำเนินงานของฉันเติมน้ำท่วมที่ฉันมีที่นี่ที่ไหนสักแห่ง (ปฏิเสธผมไม่ได้ดูแลเกี่ยวกับประสิทธิภาพดังนั้นฉันแน่ใจว่ามีหลายวิธีที่มีประสิทธิภาพมากขึ้นในการใช้มัน):
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 # เพื่อให้ตรงกับคำตอบของฉัน แต่ควรง่ายต่อการปรับให้เข้ากับภาษาอื่น ๆ และมีการใช้งานอื่น ๆ ลิงก์ด้วย)