units
This commit is contained in:
+223
@@ -0,0 +1,223 @@
|
||||
#include "gamemanager.h"
|
||||
#include "pathfinder.h"
|
||||
#include "yamlparser.h"
|
||||
#include <QDebug>
|
||||
#include <cmath>
|
||||
|
||||
GameManager& GameManager::instance()
|
||||
{
|
||||
static GameManager s_instance;
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
GameManager::GameManager()
|
||||
: m_selectedUnitId(-1), m_actionMode(ActionMode::None),
|
||||
m_movementTickDuration(30.0f), m_tickTimer(0.0f),
|
||||
m_simSpeedMultiplier(1.0f), m_nextUnitId(0), m_nextCityId(0),
|
||||
m_initialized(false)
|
||||
{
|
||||
}
|
||||
|
||||
void GameManager::init(const QString &baseDir, Matrix2D<TerrainPoint> *mapPoints, int numPoints05)
|
||||
{
|
||||
if (m_initialized) return;
|
||||
|
||||
// Load game settings
|
||||
QString gameConfigPath = baseDir + "/config/game.yaml";
|
||||
YamlNode gameRoot = YamlParser::parseFile(gameConfigPath);
|
||||
if (gameRoot.hasChild("movement_tick_duration")) {
|
||||
m_movementTickDuration = gameRoot["movement_tick_duration"].asFloat(30.0f);
|
||||
}
|
||||
|
||||
// Load unit YAML configurations
|
||||
QString unitsConfigDir = baseDir + "/config/units";
|
||||
m_unitConfigManager.loadFromDirectory(unitsConfigDir);
|
||||
|
||||
// Spawn initial demo units near starting camera position (Cam: ~28, 16 km -> hex ~37, 18)
|
||||
// Player 1 (Blue & Gold)
|
||||
spawnUnit("settler", 1, 36, 18, mapPoints, numPoints05);
|
||||
spawnUnit("warrior", 1, 37, 18, mapPoints, numPoints05);
|
||||
spawnUnit("slinger", 1, 37, 19, mapPoints, numPoints05);
|
||||
|
||||
// Player 2 (Red & White) - Opponent units
|
||||
spawnUnit("warrior", 2, 40, 18, mapPoints, numPoints05);
|
||||
spawnUnit("slinger", 2, 41, 19, mapPoints, numPoints05);
|
||||
|
||||
m_initialized = true;
|
||||
qDebug() << "GameManager initialized with" << m_units.size() << "units.";
|
||||
}
|
||||
|
||||
Unit* GameManager::spawnUnit(const QString &configId, int playerId, int tileX, int tileY,
|
||||
Matrix2D<TerrainPoint> *mapPoints, int numPoints05)
|
||||
{
|
||||
const UnitConfig *cfg = m_unitConfigManager.getConfig(configId);
|
||||
if (!cfg) {
|
||||
qWarning() << "Unit config not found:" << configId;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QVector2D w = Pathfinder::hexToWorld(tileX, tileY);
|
||||
float gz = Unit::getTerrainHeight(w.x(), w.y(), mapPoints, numPoints05);
|
||||
|
||||
int id = getNextUnitId();
|
||||
auto unit = std::make_shared<Unit>(id, playerId, *cfg, tileX, tileY, gz);
|
||||
m_units.push_back(unit);
|
||||
return unit.get();
|
||||
}
|
||||
|
||||
void GameManager::update(float deltaTime, Matrix2D<TerrainPoint> *mapPoints, int numPoints05)
|
||||
{
|
||||
// Update movement tick timer
|
||||
m_tickTimer += deltaTime * m_simSpeedMultiplier;
|
||||
if (m_tickTimer >= m_movementTickDuration) {
|
||||
m_tickTimer = std::fmod(m_tickTimer, m_movementTickDuration);
|
||||
}
|
||||
|
||||
// Update units
|
||||
for (auto &u : m_units) {
|
||||
if (!u->isDead()) {
|
||||
u->update(deltaTime, m_movementTickDuration, m_simSpeedMultiplier, mapPoints, numPoints05);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up dead units
|
||||
for (auto it = m_units.begin(); it != m_units.end(); ) {
|
||||
if ((*it)->isDead()) {
|
||||
if ((*it)->id == m_selectedUnitId) {
|
||||
m_selectedUnitId = -1;
|
||||
m_actionMode = ActionMode::None;
|
||||
}
|
||||
it = m_units.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
// Update floating texts
|
||||
for (auto it = m_floatingTexts.begin(); it != m_floatingTexts.end(); ) {
|
||||
it->life -= deltaTime;
|
||||
it->worldPos.setZ(it->worldPos.z() + deltaTime * 0.4f); // Float upward
|
||||
if (it->life <= 0.0f) {
|
||||
it = m_floatingTexts.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Unit* GameManager::getSelectedUnit()
|
||||
{
|
||||
return getUnitById(m_selectedUnitId);
|
||||
}
|
||||
|
||||
const Unit* GameManager::getSelectedUnit() const
|
||||
{
|
||||
for (const auto &u : m_units) {
|
||||
if (u->id == m_selectedUnitId) return u.get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void GameManager::selectUnit(int id)
|
||||
{
|
||||
m_selectedUnitId = id;
|
||||
m_actionMode = ActionMode::None;
|
||||
}
|
||||
|
||||
void GameManager::deselectUnit()
|
||||
{
|
||||
m_selectedUnitId = -1;
|
||||
m_actionMode = ActionMode::None;
|
||||
}
|
||||
|
||||
Unit* GameManager::getUnitAt(int tx, int ty)
|
||||
{
|
||||
for (auto &u : m_units) {
|
||||
if (!u->isDead() && u->tileX == tx && u->tileY == ty) {
|
||||
return u.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Unit* GameManager::getUnitById(int id)
|
||||
{
|
||||
for (auto &u : m_units) {
|
||||
if (u->id == id && !u->isDead()) return u.get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void GameManager::commandMoveSelected(int targetX, int targetY, Matrix2D<TerrainPoint> *mapPoints, int numPoints05)
|
||||
{
|
||||
Unit *selected = getSelectedUnit();
|
||||
if (!selected) return;
|
||||
|
||||
if (targetX == selected->tileX && targetY == selected->tileY) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::pair<int, int>> path = Pathfinder::findPath(
|
||||
selected->tileX, selected->tileY, targetX, targetY, mapPoints, numPoints05
|
||||
);
|
||||
|
||||
if (path.size() > 1) {
|
||||
selected->setPath(path);
|
||||
addFloatingText("Verplaatsen", selected->worldPos + QVector3D(0, 0, 0.8f), QColor(255, 230, 80));
|
||||
}
|
||||
}
|
||||
|
||||
void GameManager::commandAttack(Unit *target)
|
||||
{
|
||||
Unit *selected = getSelectedUnit();
|
||||
if (!selected || !target) return;
|
||||
|
||||
if (!selected->canAttack(*target)) {
|
||||
addFloatingText("Buiten bereik!", selected->worldPos + QVector3D(0, 0, 0.8f), QColor(255, 80, 80));
|
||||
return;
|
||||
}
|
||||
|
||||
float damage = (float)selected->config.attackDamage;
|
||||
selected->performAttack(*target);
|
||||
|
||||
QString dmgText = QString("-%1 HP").arg((int)damage);
|
||||
addFloatingText(dmgText, target->worldPos + QVector3D(0, 0, 0.8f), QColor(255, 50, 50));
|
||||
|
||||
if (target->isDead()) {
|
||||
addFloatingText("Verslagen!", target->worldPos + QVector3D(0, 0, 1.2f), QColor(255, 200, 50), 2.2f);
|
||||
}
|
||||
|
||||
m_actionMode = ActionMode::None;
|
||||
}
|
||||
|
||||
void GameManager::commandBuildCitySelected(Matrix2D<TerrainPoint> *mapPoints, int numPoints05)
|
||||
{
|
||||
Unit *selected = getSelectedUnit();
|
||||
if (!selected || !selected->config.canBuildCity()) return;
|
||||
|
||||
// Check if tile already has a city
|
||||
for (const auto &c : m_cities) {
|
||||
if (c.tileX == selected->tileX && c.tileY == selected->tileY) {
|
||||
addFloatingText("Al een stad hier!", selected->worldPos + QVector3D(0, 0, 0.8f), QColor(255, 80, 80));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int cId = getNextCityId();
|
||||
QString cityName = QString("Stad %1").arg(cId);
|
||||
QVector2D w = Pathfinder::hexToWorld(selected->tileX, selected->tileY);
|
||||
float gz = Unit::getTerrainHeight(w.x(), w.y(), mapPoints, numPoints05);
|
||||
|
||||
m_cities.emplace_back(cId, selected->playerId, cityName, selected->tileX, selected->tileY, QVector3D(w.x(), w.y(), gz));
|
||||
addFloatingText(QString("%1 gesticht!").arg(cityName), QVector3D(w.x(), w.y(), gz + 1.2f), QColor(80, 255, 120), 2.5f);
|
||||
|
||||
// Consuming settler
|
||||
selected->takeDamage(99999.0f);
|
||||
m_selectedUnitId = -1;
|
||||
m_actionMode = ActionMode::None;
|
||||
}
|
||||
|
||||
void GameManager::addFloatingText(const QString &text, const QVector3D &worldPos, const QColor &color, float duration)
|
||||
{
|
||||
m_floatingTexts.push_back({text, worldPos, duration, duration, color});
|
||||
}
|
||||
Reference in New Issue
Block a user