Tôi đã tìm ra cách thực hiện thuật toán dịch chuyển điểm giữa để tạo bản đồ cho trò chơi của mình. Tôi muốn tạo ra một thế giới rộng lớn vô tận, vì vậy tôi đã cố gắng vá hai bản đồ lại với nhau, nhưng chúng trông không được liền mạch. Tôi nhớ thuật toán Diamond-vuông ...
Trên trang Wikipedia cho thuật toán Diamond-vuông có ghi:
Khi được sử dụng với các giá trị góc ban đầu nhất quán, phương pháp này cũng cho phép các fractals được tạo được ghép lại với nhau mà không bị gián đoạn
Sau khi đọc xong, tôi quyết định chuyển đổi phương pháp chuyển vị giữa của mình thành phương pháp mà tôi tin là phương pháp vuông kim cương thích hợp. Tuy nhiên, nó vẫn không có vẻ liền mạch mặc dù tôi sử dụng "giá trị góc ban đầu nhất quán".
Phương pháp hoạt động hoàn hảo khác.
Đây là hai bản đồ được tạo cạnh nhau:
Như bạn có thể thấy, có những điểm không liên tục lớn (mặc dù có vẻ như chúng gần như có thể khớp với nhau). Những gì tôi viết không phải là một phương pháp hình vuông kim cương "thật", hoặc có thể tôi đang hiểu sai bài viết trên Wikipedia.
Vì vậy, nói cách khác, câu hỏi của tôi là: Điều gì sai với mã của tôi hoặc sự hiểu biết của tôi ngăn tôi ghép các bản đồ lại với nhau?
Cảm ơn rất nhiều!
public static float[][] generateMap(int power, float topLeft, float topRight, float bottomLeft, float bottomRight, float error, float persistence, boolean normalize, long seed){
Random random = new Random(seed);
int size = (int)Math.pow(2, power) + 1;
float[][] data = new float[size][size];
// these are for the normalization at the end.
// does it even do anything?
float min = MathHelper.min(topLeft, topRight, bottomLeft, bottomRight);
float max = MathHelper.max(topLeft, topRight, bottomLeft, bottomRight);
// set the corners to the initial values.
data[0][0] = topLeft;
data[size-1][size-1] = bottomRight;
data[0][size-1] = topRight;
data[size-1][0] = bottomLeft;
for (int i = 0; i < power; i++){
int square = size / (int)Math.pow(2, i);
int half = square / 2;
for (int x = 0; x < size - square; x += square){
for (int y = 0; y < size - square; y += square){
// find the values of the corners of the square.
float tl = data[y][x];
float bl = data[y + square][x];
float tr = data[y][x + square];
float br = data[y + square][x + square];
// find the values of the corners of the diamond (if they exist).
Float xt = (y - square - half >= 0) ? data[y-square-half][x+half] : null;
Float xb = (y + square + half < size) ? data[y+square+half][x+half] : null;
Float xl = (x - square - half >= 0) ? data[y+half][x-square-half] : null;
Float xr = (x + square + half < size) ? data[y+half][x+square+half] : null;
// set the square's center to the average of the square's corners plus a random error.
float centerVal = (tl + bl + tr + br) / 4.0f;
centerVal += ((random.nextFloat() * 2) - 1) * error;
data[y+half][x+half] = centerVal;
// set the diamonds' centers to the average of the diamonds' corners (that exist) plus a random error.
float leftVal = (tl + bl + centerVal + (xl != null ? xl : 0)) / (3.0f + (xl != null ? 1.0f : 0.0f));
leftVal += ((random.nextFloat() * 2) - 1) * error;
data[y+half][x] = leftVal;
float rightVal = (tr + br + centerVal + (xr != null ? xr : 0)) / (3.0f + (xr != null ? 1.0f : 0.0f));
rightVal += ((random.nextFloat() * 2) - 1) * error;
data[y+half][x+square] = rightVal;
float topVal = (tl + tr + centerVal + (xt != null ? xt : 0)) / (3.0f + (xt != null ? 1.0f : 0.0f));
topVal += ((random.nextFloat() * 2) - 1) * error;
data[y][x+half] = topVal;
float bottomVal = (bl + br + centerVal + (xb != null ? xb : 0)) / (3.0f + (xb != null ? 1.0f : 0.0f));
bottomVal += ((random.nextFloat() * 2) - 1) * error;
data[y+square][x+half] = bottomVal;
max = MathHelper.max(max, centerVal, leftVal, rightVal, topVal, bottomVal);
min = MathHelper.min(min, centerVal, leftVal, rightVal, topVal, bottomVal);
}
}
// reduce random error.
error *= persistence;
}
// does this even do anything?
if (normalize) {
float div = max - min;
for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++)
data[i][j] /= div;
}
return data;
}