我正在开发一款游戏,我们根据柏林噪声生成等距瓷砖世界。 Perlin 噪声用于创建预览图像,其中不同的地形类型和资源(例如水、草、山脉、煤炭和黄金)由特定颜色表示。我正在寻求帮助来创建一种方法,该方法可以扫描预览图像并将颜色转换为相应的等距图块以形成游戏世界。
当前设置:
void NewGameState::generatePerlinNoise() {
// Perlin noise is generated for terrain elevation and resource patches.
const int noiseWidth = 600;
const int noiseHeight = 400;
sf::Uint8* pixels = new sf::Uint8[noiseWidth * noiseHeight * 4];
for (int x = 0; x < noiseWidth; x++) {
for (int y = 0; y < noiseHeight; y++) {
// Calculate Perlin noise value and assign colors based on thresholds
float val = perlin(x * 0.05f, y * 0.05f, seed);
sf::Uint8 r = 0, g = 0, b = 0;
if (val < 0.25f) {
r = 0; g = 0; b = 255; // Water (blue)
} else if (val < 0.55f) {
r = 34; g = 139; b = 34; // Grass (green)
} else if (val < 0.75f) {
r = 169; g = 169; b = 169; // Mountain (grey)
}
// Set pixel data
int index = (y * noiseWidth + x) * 4;
pixels[index] = r;
pixels[index + 1] = g;
pixels[index + 2] = b;
pixels[index + 3] = 255; // Alpha
}
}
perlinTexture.create(noiseWidth, noiseHeight);
perlinTexture.update(pixels);
perlinSprite.setTexture(perlinTexture);
delete[] pixels;
}
void TileRenderer::generateWorld() {
float frequency = 0.05f;
int seed = rand();
for (int y = 0; y < worldHeight; ++y) {
std::vector<std::string> row;
for (int x = 0; x < worldWidth; ++x) {
float noiseValue = perlin(x * frequency, y * frequency, seed);
if (noiseValue < 0.25f) {
row.push_back("water");
} else if (noiseValue < 0.55f) {
row.push_back("grass");
} else if (noiseValue < 0.75f) {
row.push_back("mountain");
}
}
worldMap.push_back(row);
}
}
void TileRenderer::render(sf::RenderWindow &window) {
float tileWidth = 132.f;
float tileHeight = 99.f;
for (int y = 0; y < worldHeight; ++y) {
for (int x = 0; x < worldWidth; ++x) {
sf::Sprite sprite;
sprite.setTexture(tileTextures[worldMap[y][x]]);
float posX = (x - y) * (tileWidth / 2.0f);
float posY = (x + y) * (tileHeight / 2.0f);
sprite.setPosition(posX, posY);
window.draw(sprite);
}
}
}
问题:
我正在尝试将基于 Perlin 噪声的预览图像直接转换为等距图块世界。我不想再次使用 Perlin 噪声值来生成世界,而是扫描预览图像的颜色(蓝色 = 水,绿色 = 草等)并放置相应的图块。
我需要什么帮助:
如果需要,我还可以发布预览图像的输出以及我目前创建的图块,不幸的是,它们与图像不相似。
不要使用表示层来保持状态。 相反,我们首先定义一些图块类型:
enum class TileType : uint8_t {
Water,
Grass,
Mountain,
};
struct Tile {
TileType base;
};
您的
NewGameState::generatePerlinNoise
现在可以生成一个std::vector<std::vector<Tile>> worldMap
。之后您可以从世界地图创建 sf::Image
和 sf::Texture
:
sf::Image img{noiseWidth, noiseHeight};
static const std::map<TileType, sf::Color> tileToColor = {
{ TileType::Water, sf::Color{0, 0, 255} },
{ TileType::Grass, sf::Color{34, 139, 34} },
{ TileType::Mountain, sf::Color{169, 169, 169} },
};
for (int x = 0; x < noiseWidth; x++) {
for (int y = 0; y < noiseHeight; y++) {
img.setPixel(x, y, tileToColor[worldMap[y][x].base]);
}
}
perlinTexture.loadFromImage(img);
最后,将
tileTextures
修改为 std::map<TileType, sf::Texture>
即可完成。
如果您想要存储更多状态而不仅仅是图块类型(项目、角色、建筑物等),您现在只需向
struct Tile
添加成员变量和方法,而无需更改其余代码。