Đảo bỏ
Tôi đã từng làm điều này trước đây trong một trong những trò chơi của mình. Để thoát khỏi các hòn đảo bên ngoài, quá trình cơ bản là:
- Đầu tiên phải có một sự đảm bảo rằng trung tâm của bản đồ sẽ luôn thuộc về vùng đất chính và mỗi pixel bắt đầu là "Vùng đất" hoặc "Nước" (tức là các màu khác nhau).
- Sau đó, thực hiện lấp lũ bốn hướng bắt đầu từ trung tâm bản đồ và trải khắp mọi ô "Đất". Đánh dấu mỗi pixel được truy cập bởi vùng lũ này là một loại khác nhau, chẳng hạn như "MainLand".
- Cuối cùng đi qua toàn bộ bản đồ và chuyển đổi bất kỳ pixel "Đất" nào còn lại thành "Nước để thoát khỏi các đảo khác.
Loại bỏ hồ
Đối với việc loại bỏ các lỗ (hoặc hồ) bên trong hòn đảo, bạn thực hiện một quy trình tương tự nhưng bắt đầu từ các góc của bản đồ và lan truyền qua các ô "Nước". Điều này sẽ cho phép bạn phân biệt "Biển" với các khối nước khác, và sau đó bạn có thể thoát khỏi chúng giống như bạn đã thoát khỏi các đảo trước đây.
Thí dụ
Hãy để tôi khai thác việc thực hiện lấp lũ mà tôi có ở đây ở đâu đó (từ chối trách nhiệm, tôi không quan tâm đến hiệu quả, vì vậy tôi chắc chắn có nhiều cách hiệu quả hơn để thực hiện nó):
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);
}
Tôi đã sử dụng điều này như một bước đầu tiên để thoát khỏi hồ trong trò chơi của tôi. Sau khi gọi điều đó, tất cả những gì tôi phải làm là một cái gì đó như:
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;
}
Chỉnh sửa
Thêm một số thông tin bổ sung dựa trên các ý kiến. Trong trường hợp không gian tìm kiếm của bạn quá lớn, bạn có thể gặp phải tình trạng tràn ngăn xếp khi sử dụng phiên bản đệ quy của thuật toán. Đây là một liên kết trên stackoverflow (ý định chơi chữ :-)) với phiên bản thuật toán không đệ quy, sử dụng Stack<T>
thay thế (cũng trong C # để khớp với câu trả lời của tôi, nhưng nên dễ dàng thích nghi với các ngôn ngữ khác và có các triển khai khác trên đó liên kết quá).