First approach of area generation

This commit is contained in:
sebastian 2026-02-14 18:18:58 +01:00
parent dad3a4e0f3
commit 762550fccf
2 changed files with 127 additions and 41 deletions

View File

@ -4,7 +4,12 @@
#include "MapGenerator.h"
#include <queue>
#include <unordered_set>
struct TileInfo {
int q, r;
EntityID id;
};
float MapGenerator::hexRadius = 10.0f;
@ -20,51 +25,130 @@ void MapGenerator::init(Loader &loader, float hexRadius) {
}
void MapGenerator::generateHexMap(Map &map, int width, int height, EntityManager &entityManager) {
Random random;
Random random;
map.clear(entityManager);
map.clear(entityManager);
float xOffset = hexRadius * std::sqrt(3.0f);
float zOffset = hexRadius * 1.5f;
float xOffset = hexRadius * std::sqrt(3.0f);
float zOffset = hexRadius * 1.5f;
for (int r = 0; r < height; ++r) {
for (int q = 0; q < width; ++q) {
// Pointy-top Hexes
float x = xOffset * (q + 0.5f * (r % 2));
float z = zOffset * r;
glm::vec3 worldPos = glm::vec3(x, 0.0f, z);
float radius = hexRadius;
EntityID entityID = entityManager.createEntity();
float randomValue = random.randomFloat(0.0f, 1.0f);
RessourceType resourceType = RessourceType::NONE;
std::shared_ptr<TexturedModel> hexModel = AssetManager::getModel("hexModelNone");
std::vector<EntityID> tileEntities;
std::string modelName = "hexModelNone";
if (randomValue < 0.5f) {
resourceType = RessourceType::WOOD;
ForestTileGenerator forestTileGenerator;
tileEntities = forestTileGenerator.generateHexTile(entityManager, random, worldPos);
hexModel = AssetManager::getModel("hexModelWood");
modelName = "hexModelWood";
} else if (randomValue < 0.75f) {
resourceType = RessourceType::STONE;
hexModel = AssetManager::getModel("hexModelStone");
modelName = "hexModelStone";
for (int r = 0; r < height; ++r) {
for (int q = 0; q < width; ++q) {
// Pointy-top Hexes
float x = xOffset * (q + 0.5f * (r % 2));
float z = zOffset * r;
glm::vec3 worldPos = glm::vec3(x, 0.0f, z);
float radius = hexRadius;
EntityID entityID = entityManager.createEntity();
float randomValue = random.randomFloat(0.0f, 1.0f);
RessourceType resourceType = RessourceType::NONE;
std::shared_ptr<TexturedModel> hexModel = AssetManager::getModel("hexModelNone");
std::vector<EntityID> tileEntities;
std::string modelName = "hexModelNone";
if (randomValue < 0.5f) {
resourceType = RessourceType::WOOD;
ForestTileGenerator forestTileGenerator;
tileEntities = forestTileGenerator.generateHexTile(entityManager, random, worldPos);
hexModel = AssetManager::getModel("hexModelWood");
modelName = "hexModelWood";
} else if (randomValue < 0.75f) {
resourceType = RessourceType::STONE;
hexModel = AssetManager::getModel("hexModelStone");
modelName = "hexModelStone";
}
const auto transformComponent = std::make_shared<TransformComponent>(worldPos, glm::vec3(0), 1.0f);
const auto modelComponent = std::make_shared<ModelComponent>(hexModel, modelName);
const auto tileHighlightComponent = std::make_shared<TileRenderComponent>(false);
const auto tileGameplayComponent = std::make_shared<TileGameplayComponent>(q, r, radius, resourceType);
tileGameplayComponent->entitiesOnTile = tileEntities;
entityManager.addComponent(entityID, transformComponent);
entityManager.addComponent(entityID, modelComponent);
entityManager.addComponent(entityID, tileHighlightComponent);
entityManager.addComponent(entityID, tileGameplayComponent);
entityManager.addComponent(entityID, std::make_shared<MapEntityComponent>());
}
}
assignOwners(entityManager, 2);
}
void MapGenerator::assignOwners(EntityManager &entityManager, int numPlayers) {
Random random;
std::vector<TileInfo> allTiles;
for (EntityID id: entityManager.getAllEntities()) {
if (auto tileComponent = entityManager.getComponent<TileGameplayComponent>(id)) {
allTiles.push_back({tileComponent->q, tileComponent->r, id});
}
}
int maxTilesPerPlayer = static_cast<int>(allTiles.size() / numPlayers * (1.f / numPlayers)); // z.B. 60% der Map
std::unordered_set<EntityID> assigned;
//1 Seets pro Spieler
std::vector<EntityID> seeds;
for (int player = 0; player < numPlayers; ++player) {
EntityID seed = allTiles[random.randomInt(0, static_cast<int>(allTiles.size()))].id;
seeds.push_back(seed);
entityManager.addComponent(seed, std::make_shared<OwnerComponent>(player-1));
}
// 2. Expansion
bool changed = true;
while (changed) {
changed = false;
for (PlayerID player = 0; player < static_cast<uint32_t>(numPlayers); ++player) {
// Finde alle Tiles des Spielers
int ownedCount = 0;
for (TileInfo& tile : allTiles) {
if (assigned.count(tile.id) == 0) continue;
auto owner = entityManager.getComponent<OwnerComponent>(tile.id);
if (owner && owner->playerID == player) {
++ownedCount;
}
}
const auto transformComponent = std::make_shared<TransformComponent>(worldPos, glm::vec3(0), 1.0f);
const auto modelComponent = std::make_shared<ModelComponent>(hexModel, modelName);
const auto tileHighlightComponent = std::make_shared<TileRenderComponent>(false);
const auto tileGameplayComponent = std::make_shared<TileGameplayComponent>(q, r, radius, resourceType);
tileGameplayComponent->entitiesOnTile = tileEntities;
std::vector<EntityID> borderTiles;
for (TileInfo& tile : allTiles) {
auto owner = entityManager.getComponent<OwnerComponent>(tile.id);
if (!owner || owner->playerID != player) continue;
entityManager.addComponent(entityID, transformComponent);
entityManager.addComponent(entityID, modelComponent);
entityManager.addComponent(entityID, tileHighlightComponent);
entityManager.addComponent(entityID, tileGameplayComponent);
entityManager.addComponent(entityID, std::make_shared<MapEntityComponent>());
//Todo replace with area system
entityManager.addComponent(entityID, std::make_shared<OwnerComponent>(random.randomInt(0,4)));
for (TileInfo& neighbor : allTiles) {
auto neighborOwner = entityManager.getComponent<OwnerComponent>(neighbor.id);
if (neighborOwner || assigned.count(neighbor.id)) continue;
if (areHexNeighbors(tile.q, tile.r, neighbor.q, neighbor.r)) {
borderTiles.push_back(neighbor.id);
}
}
}
if (ownedCount >= maxTilesPerPlayer) continue;
// Zufällige Auswahl eines Nachbarn zum expandieren
if (!borderTiles.empty()) {
EntityID newTile = borderTiles[random.randomInt(0, static_cast<int>(borderTiles.size()-1))];
entityManager.addComponent(newTile, std::make_shared<OwnerComponent>(player));
assigned.insert(newTile);
changed = true;
}
}
}
}
}
bool MapGenerator::areHexNeighbors(int q1, int r1, int q2, int r2) {
// Hex axial neighbor differences
static const std::vector<std::pair<int,int>> directions = {
{+1, 0}, {+1, -1}, {0, -1},
{-1, 0}, {-1, +1}, {0, +1}
};
for (auto [dq, dr] : directions) {
if (q1 + dq == q2 && r1 + dr == r2) return true;
}
return false;
}

View File

@ -30,7 +30,9 @@ public:
static void init(Loader& loader, float hexRadius);
static void generateHexMap(Map& map, int width, int height, EntityManager& entityManager);
std::vector<MapArea> generateAreas(const EntityManager &em);
static void assignOwners(EntityManager &entityManager, int numPlayers);
static bool areHexNeighbors(int tile_q, int tile_r, int neighbor_q, int neighbor_r);
private: