将 Perlin 噪声预览转换为等距平铺世界所需的想法

问题描述 投票:0回答:1

我正在开发一款游戏,我们根据柏林噪声生成等距瓷砖世界。 Perlin 噪声用于创建预览图像,其中不同的地形类型和资源(例如水、草、山脉、煤炭和黄金)由特定颜色表示。我正在寻求帮助来创建一种方法,该方法可以扫描预览图像并将颜色转换为相应的等距图块以形成游戏世界。

当前设置:

  1. Perlin 噪声生成:在 NewGameState 中,我们使用 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;
}

  1. 图块世界生成:目前,图块世界是直接根据 TileRenderer 中的 Perlin 噪声值生成的。我想用扫描预览图像并根据颜色分配图块的系统来替换它。
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);
    }
}

  1. 渲染世界:分配图块后,游戏将使用预加载的纹理渲染等距世界。
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 噪声值来生成世界,而是扫描预览图像的颜色(蓝色 = 水,绿色 = 草等)并放置相应的图块。

我需要什么帮助:

  • 如何扫描预览图像并将颜色(例如,蓝色表示水)映射到图块。
  • 一种确保从预览图像到等距世界 1:1 平移的方法。

如果需要,我还可以发布预览图像的输出以及我目前创建的图块,不幸的是,它们与图像不相似。

c++ sfml tile perlin-noise
1个回答
0
投票

不要使用表示层来保持状态。 相反,我们首先定义一些图块类型:

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
添加成员变量和方法,而无需更改其余代码。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.