gpt4 book ai didi

java - 菱形和正方形算法不起作用

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:42:37 25 4
gpt4 key购买 nike

我正在制作分形地形,但无论尝试什么,它总是看起来完全随机。我一直在遵循 Diamonds and Squares 算法,如解释的那样 here .我该怎么做才能解决这个问题?

这是我的地形类:

package game;

import java.util.Random;

public class Terrain {

Panel panel;

public Terrain(Panel panel) {
this.panel = panel;
generateTerrain();
}

private void generateTerrain() {
Random rand = new Random();

int seed = rand.nextInt(panel.colors.length);
int sideLength = panel.mapSize - 1;
int halfSideLength;
int average;

panel.map[0][0] = seed;
panel.map[panel.mapSize - 1][0] = seed;
panel.map[0][panel.mapSize - 1] = seed;
panel.map[panel.mapSize - 1][panel.mapSize - 1] = seed;

while (sideLength > 0) {
halfSideLength = sideLength / 2;
for (int x = 0; x < panel.mapSize - 1; x += sideLength) {
for (int y = 0; y < panel.mapSize - 1; y += sideLength) {
average = panel.map[x][y]
+ panel.map[x + sideLength][y]
+ panel.map[x][y + sideLength]
+ panel.map[x + sideLength][y + sideLength];
average /= 4;
average += rand.nextInt(8);
panel.map[x + halfSideLength][y + halfSideLength] = average;
}
}
for (int x = 0; x < panel.mapSize - 1; x += sideLength) {
for (int y = 0; y < panel.mapSize - 1; y += sideLength) {
average = panel.map[x][y]
+ panel.map[x + halfSideLength][y]
+ panel.map[x][y + sideLength]
+ panel.map[x + halfSideLength][y + halfSideLength];
average /= 4;
panel.map[x][y] = average;
if (x == 0) {
panel.map[panel.mapSize - 1][y] = average;
}
if (y == 0) {
panel.map[x][panel.mapSize - 1] = average;
}
}
}
sideLength /= 2;
}
}
}

这是我的面板类:

package game;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Panel extends JPanel implements ActionListener {

Terrain currentTerrain;

boolean upPressed = false;
boolean rightPressed = false;
boolean downPressed = false;
boolean leftPressed = false;

int tileSize = 1;
int mapSize = 1025;

int deltaX = 0;
int deltaY = 0;
int x = 0;
int y = 0;

int map[][] = new int[mapSize][mapSize];

Color[] colors = {
new Color(0, 0, 180),
new Color(0, 0, 255),
new Color(0, 150, 255),
new Color(255, 255, 180),
new Color(220, 220, 120),
new Color(200, 200, 60),
new Color(0, 200, 0),
new Color(0, 180, 0),
new Color(0, 160, 0),
new Color(0, 140, 0),
new Color(0, 120, 0),
new Color(0, 100, 0),
new Color(0, 80, 0),
new Color(0, 60, 0),
new Color(0, 40, 0),
new Color(40, 40, 40),
new Color(60, 60, 60),
new Color(80, 80, 80),
new Color(100, 100, 100),
new Color(120, 120, 120),
new Color(255, 255, 255)
};


public Panel(Main main) {
setPreferredSize(main.getSize());
setFocusable(true);
setBackground(Color.WHITE);
add(new KeyBindings(this));
currentTerrain = new Terrain(this);
new Timer(1000 / 120, this).start();
}

private void tick() {
if (upPressed) {
deltaY += 10;
} else if (downPressed) {
deltaY -= 10;
}
if (rightPressed) {
deltaX -= 10;
} else if (leftPressed) {
deltaX += 10;
}
repaint();
}

@Override
public void actionPerformed(ActionEvent e) {
tick();
}

@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);

x = 0;
y = 0;

for (int[] rowData : map) {
for (int cellData : rowData) {
int v = cellData;
if(v < 0) {
v = 0;
} else if(v > colors.length - 1) {
v = colors.length - 1;
}
g.setColor(colors[v]);
g.fillRect(x + deltaX, y + deltaY, tileSize, tileSize);
x += tileSize;
if(x == mapSize * tileSize) {
x = 0;
y += tileSize;
}
}
}
}
}

最佳答案

您弄错了算法的钻石阶段。菱形的中心是正方形边的中点。它们最好在两个单独的循环中处理:一个用于垂直中点,第二个用于水平中点。在 map 的边缘,钻石的尖端会伸出 map 。您可以通过将它们“折叠”到 map 中来解决这个问题,例如在左边,右边的点会被考虑两次。

所以代码应该是:

function generateTerrain() {
int seed = rand.nextInt(colors.length);
int sideLength = mapSize - 1;
int halfSideLength;
int average;
int offset = 8;

map[0][0] = seed;
map[mapSize - 1][0] = seed;
map[0][mapSize - 1] = seed;
map[mapSize - 1][mapSize - 1] = seed;

while (sideLength > 0) {
halfSideLength /= 2;
for (int x = 0; x < mapSize - 1; x += sideLength) {
for (int y = 0; y < mapSize - 1; y += sideLength) {
average = map[x][y]
+ map[x + sideLength][y]
+ map[x][y + sideLength]
+ map[x + sideLength][y + sideLength];
average /= 4;
average += rand.nextInt(offset);

map[x + halfSideLength][y + halfSideLength] = average;
}
}

for (int x = 0; x < mapSize - 1; x += sideLength) {
for (int y = 0; y < mapSize; y += sideLength) {
int yTop = y - halfSideLength;
int yBottom = y + halfSideLength;

if (yTop < 0) yTop = y + halfSideLength;
if (yBottom > mapSize - 1) yBottom = y - halfSideLength;

average = map[x][y]
+ map[x + sideLength][y]
+ map[x + halfSideLength][yTop]
+ map[x + halfSideLength][yBottom];
average = /= 4;

map[x + halfSideLength][y] = average;
}
}

for (int x = 0; x < mapSize; x += sideLength) {
for (int y = 0; y < mapSize - 1; y += sideLength) {
int xLeft = x - halfSideLength;
int xRight = x + halfSideLength;

if (xLeft < 0) xLeft = x + halfSideLength;
if (xRight > mapSize - 1) xRight = x - halfSideLength;

average = map[x][y]
+ map[x][y + sideLength]
+ map[xRight][y + halfSideLength]
+ map[xRight][y + halfSideLength];
average /= 4;

map[x][y + halfSideLength] = average;
}
}

sideLength /= 2;
}
}

(注意:我已经从你的代码开始工作,但是将它转换成 Javascript 并转换回来,所以它可能仍然存在一些 Java 错误。但我认为这两个循环的想法很清楚。)

这会产生非常嘈杂的 map 。通常,每次将边长减半时,随机偏移量(代码中的 8)都会减少一个常数。 map 的平滑度可以通过这个参数来控制,玩起来很有趣。在您的例子中,参数是 1.0。逼真的 map 的一个很好的系数是 0.65 左右。

您的方法还有另一个问题:您始终使用窄整数。我在这里使用“窄”是指整数的粒度,即 1,等于 map 中的颜色变化。这并没有为一种颜色内的随机变化提供很大的范围。最好使用 float 或范围更广的整数来生成 map ,然后将这些值映射到您的颜色。

例如,假设您使用介于 0.0 和 1.0 之间的 float :然后您可以将低于 0.1 的值映射为深绿色,将低于 0.2 的值映射为浅绿色,依此类推,直到高于 0.9 的值变为白色。这将提供更平滑的带状外观,如您链接的文章部分下方的云图片。

另一件事是,您从拐角处的随机值开始,然后在打印 map 时将值限制在颜色范围内。您添加的随机偏移量始终为正,因此如果您从“高”颜色开始,您很可能会得到一张大部分为白色的图片。事实上,您不会得到任何低于起始值的颜色。您可以从中间颜色开始,并允许负随机偏移和正随机偏移来避免这种情况。或者,您可以在生成 map 后根据最低值和最高值对其进行归一化。

关于java - 菱形和正方形算法不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30228244/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com