Implement tile-targeted road route construction and OpenGL 3D layered road rendering
This commit is contained in:
+158
-6
@@ -862,7 +862,107 @@ void QSceneRenderer::drawPathAndRange(QPainter &painter, Unit *unit, const QMatr
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Attack range visualization if Attack mode is active
|
||||
// 2. Road Route visualization if unit is constructing a multi-tile road route
|
||||
if (unit->hasRoadRoute()) {
|
||||
QPainterPath routeLine;
|
||||
bool first = true;
|
||||
for (size_t i = unit->roadRouteIndex; i < unit->roadRoute.size(); ++i) {
|
||||
auto hex = unit->roadRoute[i];
|
||||
QVector2D w = Pathfinder::hexToWorld(hex.first, hex.second);
|
||||
float z = Unit::getTerrainHeight(w.x(), w.y(), m_point, m_numPoints05);
|
||||
bool inFront = false;
|
||||
QPointF sPos = UnitRenderer::projectToScreen(QVector3D(w.x(), w.y(), z + 0.06f), Projection, vMatrix, width(), height(), inFront);
|
||||
if (inFront) {
|
||||
if (first) {
|
||||
routeLine.moveTo(sPos);
|
||||
first = false;
|
||||
} else {
|
||||
routeLine.lineTo(sPos);
|
||||
}
|
||||
painter.setPen(QPen(QColor(140, 95, 30, 200), 1.2));
|
||||
painter.setBrush(QColor(255, 215, 60, 220));
|
||||
painter.drawEllipse(sPos, 3.5, 3.5);
|
||||
}
|
||||
}
|
||||
painter.setPen(QPen(QColor(255, 195, 45, 230), 2.8, Qt::DashLine));
|
||||
painter.setBrush(Qt::NoBrush);
|
||||
painter.drawPath(routeLine);
|
||||
|
||||
auto destHex = unit->roadRoute.back();
|
||||
QVector2D destW = Pathfinder::hexToWorld(destHex.first, destHex.second);
|
||||
float destZ = Unit::getTerrainHeight(destW.x(), destW.y(), m_point, m_numPoints05);
|
||||
bool inFront = false;
|
||||
QPointF sDest = UnitRenderer::projectToScreen(QVector3D(destW.x(), destW.y(), destZ + 0.06f), Projection, vMatrix, width(), height(), inFront);
|
||||
if (inFront) {
|
||||
float pulse = (std::sin(m_elapsedTimer.elapsed() * 0.008f) + 1.0f) * 0.5f;
|
||||
painter.setPen(QPen(QColor(255, 215, 50, (int)(180 + pulse * 75)), 2.2));
|
||||
painter.setBrush(QColor(255, 190, 40, 45));
|
||||
painter.drawEllipse(sDest, 14.0f, 14.0f);
|
||||
painter.drawLine(sDest.x() - 18, sDest.y(), sDest.x() + 18, sDest.y());
|
||||
painter.drawLine(sDest.x(), sDest.y() - 18, sDest.x(), sDest.y() + 18);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Road Build targeting preview when in ActionMode::BuildRoad
|
||||
if (GameManager::instance().currentActionMode() == ActionMode::BuildRoad && unit->config.canBuildRoad()) {
|
||||
int hx = -1, hy = -1;
|
||||
if (screenToHex(m_mouseCurrentPos, vMatrix, hx, hy) && (hx != unit->tileX || hy != unit->tileY)) {
|
||||
if (TerrainMovementManager::instance().isHexPassable(hx, hy, MovementDomain::Land, m_point, m_numPoints05, &unit->config)) {
|
||||
auto preview = Pathfinder::findPath(unit->tileX, unit->tileY, hx, hy, MovementDomain::Land, m_point, m_numPoints05, &unit->config);
|
||||
if (preview.size() > 1) {
|
||||
QPainterPath previewLine;
|
||||
bool first = true;
|
||||
for (const auto &p : preview) {
|
||||
QVector2D w = Pathfinder::hexToWorld(p.first, p.second);
|
||||
float z = Unit::getTerrainHeight(w.x(), w.y(), m_point, m_numPoints05);
|
||||
bool inFront = false;
|
||||
QPointF sPos = UnitRenderer::projectToScreen(QVector3D(w.x(), w.y(), z + 0.06f), Projection, vMatrix, width(), height(), inFront);
|
||||
if (inFront) {
|
||||
if (first) {
|
||||
previewLine.moveTo(sPos);
|
||||
first = false;
|
||||
} else {
|
||||
previewLine.lineTo(sPos);
|
||||
}
|
||||
painter.setPen(QPen(QColor(160, 110, 40, 200), 1.0));
|
||||
painter.setBrush(QColor(255, 230, 90, 230));
|
||||
painter.drawEllipse(sPos, 3.5, 3.5);
|
||||
}
|
||||
}
|
||||
painter.setPen(QPen(QColor(255, 220, 60, 240), 3.0, Qt::DashLine));
|
||||
painter.setBrush(Qt::NoBrush);
|
||||
painter.drawPath(previewLine);
|
||||
|
||||
// Destination reticle
|
||||
QVector2D destW = Pathfinder::hexToWorld(hx, hy);
|
||||
float destZ = Unit::getTerrainHeight(destW.x(), destW.y(), m_point, m_numPoints05);
|
||||
bool inFront = false;
|
||||
QPointF sDest = UnitRenderer::projectToScreen(QVector3D(destW.x(), destW.y(), destZ + 0.06f), Projection, vMatrix, width(), height(), inFront);
|
||||
if (inFront) {
|
||||
float pulse = (std::sin(m_elapsedTimer.elapsed() * 0.01f) + 1.0f) * 0.5f;
|
||||
painter.setPen(QPen(QColor(255, 225, 70, (int)(180 + pulse * 75)), 2.5));
|
||||
painter.setBrush(QColor(255, 210, 50, 50));
|
||||
painter.drawEllipse(sDest, 16.0f, 16.0f);
|
||||
painter.drawLine(sDest.x() - 22, sDest.y(), sDest.x() + 22, sDest.y());
|
||||
painter.drawLine(sDest.x(), sDest.y() - 22, sDest.x(), sDest.y() + 22);
|
||||
|
||||
QString targetTip = Localization::instance().get("ui.unit.btn_road_route", "Route (%1 hexes)").arg(preview.size() - 1);
|
||||
painter.setFont(QFont("sans-serif", 8, QFont::Bold));
|
||||
QFontMetrics fm = painter.fontMetrics();
|
||||
int tw = fm.horizontalAdvance(targetTip) + 16;
|
||||
QRect tipRect((int)sDest.x() - tw / 2, (int)sDest.y() - 34, tw, 20);
|
||||
painter.setBrush(QColor(20, 24, 34, 230));
|
||||
painter.setPen(QPen(QColor(255, 215, 60), 1.2));
|
||||
painter.drawRoundedRect(tipRect, 4, 4);
|
||||
painter.setPen(QColor(255, 235, 120));
|
||||
painter.drawText(tipRect, Qt::AlignCenter, targetTip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Attack range visualization if Attack mode is active
|
||||
if (GameManager::instance().currentActionMode() == ActionMode::Attack) {
|
||||
int range = unit->config.attackRange;
|
||||
for (const auto &u : GameManager::instance().getUnits()) {
|
||||
@@ -2367,7 +2467,19 @@ void QSceneRenderer::mousePressEvent(QMouseEvent *event)
|
||||
} else if (ab.actionId == "boerderij_bouwen" || ab.actionId == "build_farm") {
|
||||
GameManager::instance().commandBuildFarmSelected(m_point, m_numPoints05);
|
||||
} else if (ab.actionId == "build_road" || ab.actionId == "weg_bouwen") {
|
||||
GameManager::instance().commandBuildRoadSelected(m_point, m_numPoints05);
|
||||
Unit *sel = GameManager::instance().getSelectedUnit();
|
||||
if (sel && sel->hasRoadRoute()) {
|
||||
sel->clearRoadRoute();
|
||||
sel->cancelBuilding();
|
||||
GameManager::instance().setActionMode(ActionMode::None);
|
||||
GameManager::instance().addFloatingText(
|
||||
Localization::instance().get("ui.unit.road_route_cancelled", "Road route cancelled"),
|
||||
sel->worldPos + QVector3D(0, 0, 0.8f), QColor(255, 120, 100));
|
||||
} else if (GameManager::instance().currentActionMode() == ActionMode::BuildRoad) {
|
||||
GameManager::instance().setActionMode(ActionMode::None);
|
||||
} else {
|
||||
GameManager::instance().setActionMode(ActionMode::BuildRoad);
|
||||
}
|
||||
}
|
||||
update();
|
||||
return;
|
||||
@@ -2422,6 +2534,11 @@ void QSceneRenderer::mousePressEvent(QMouseEvent *event)
|
||||
GameManager::instance().setActionMode(ActionMode::None);
|
||||
update();
|
||||
return;
|
||||
} else if (GameManager::instance().currentActionMode() == ActionMode::BuildRoad) {
|
||||
GameManager::instance().commandBuildRoadToTileSelected(hitX, hitY, m_point, m_numPoints05);
|
||||
GameManager::instance().setActionMode(ActionMode::None);
|
||||
update();
|
||||
return;
|
||||
} else if (GameManager::instance().currentActionMode() == ActionMode::Attack) {
|
||||
Unit *enemy = GameManager::instance().getUnitAt(hitX, hitY);
|
||||
if (enemy && enemy->playerId != selected->playerId) {
|
||||
@@ -2450,6 +2567,11 @@ void QSceneRenderer::mousePressEvent(QMouseEvent *event)
|
||||
update();
|
||||
return;
|
||||
} else if (event->button() == Qt::RightButton) {
|
||||
if (GameManager::instance().currentActionMode() == ActionMode::BuildRoad) {
|
||||
GameManager::instance().setActionMode(ActionMode::None);
|
||||
update();
|
||||
return;
|
||||
}
|
||||
// Right click: Attack enemy unit or move selected unit directly to hex!
|
||||
if (selected) {
|
||||
Unit *enemy = GameManager::instance().getUnitAt(hitX, hitY);
|
||||
@@ -2627,11 +2749,28 @@ void QSceneRenderer::keyPressEvent(QKeyEvent *e)
|
||||
GameManager::instance().commandBuildFarmSelected(m_point, m_numPoints05);
|
||||
}
|
||||
else if (e->key() == Qt::Key_R && sel && sel->config.canBuildRoad()) {
|
||||
GameManager::instance().commandBuildRoadSelected(m_point, m_numPoints05);
|
||||
if (sel->hasRoadRoute()) {
|
||||
sel->clearRoadRoute();
|
||||
sel->cancelBuilding();
|
||||
GameManager::instance().setActionMode(ActionMode::None);
|
||||
GameManager::instance().addFloatingText(
|
||||
Localization::instance().get("ui.unit.road_route_cancelled", "Road route cancelled"),
|
||||
sel->worldPos + QVector3D(0, 0, 0.8f), QColor(255, 120, 100));
|
||||
} else {
|
||||
GameManager::instance().setActionMode(
|
||||
GameManager::instance().currentActionMode() == ActionMode::BuildRoad ? ActionMode::None : ActionMode::BuildRoad
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (e->key() == Qt::Key_Escape) {
|
||||
if (GameManager::instance().currentActionMode() != ActionMode::None) {
|
||||
GameManager::instance().setActionMode(ActionMode::None);
|
||||
} else if (sel && sel->hasRoadRoute()) {
|
||||
sel->clearRoadRoute();
|
||||
sel->cancelBuilding();
|
||||
GameManager::instance().addFloatingText(
|
||||
Localization::instance().get("ui.unit.road_route_cancelled", "Road route cancelled"),
|
||||
sel->worldPos + QVector3D(0, 0, 0.8f), QColor(255, 120, 100));
|
||||
} else if (sel && sel->hasQueuedAction()) {
|
||||
sel->clearActionQueue();
|
||||
GameManager::instance().addFloatingText(
|
||||
@@ -2787,11 +2926,25 @@ void QSceneRenderer::paintGL()
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Render 3D Units & Cities (Cylinders & Bastions)
|
||||
// 2. Render 3D Roads (above terrain elevation, writes depth so units and cities render on top)
|
||||
float fSunAngle = 45.0f;
|
||||
QVector3D vSunPos(-sin(fSunAngle * PI / 180.0f), -cos(fSunAngle * PI / 180.0f), 0.6f);
|
||||
vSunPos.normalize();
|
||||
|
||||
m_unitRenderer.renderRoads(
|
||||
GameManager::instance().getTileRoads(),
|
||||
GameManager::instance().roadConfigs(),
|
||||
m_point,
|
||||
m_numPoints05,
|
||||
Projection,
|
||||
vMatrix,
|
||||
vSunPos,
|
||||
cityViewRadius,
|
||||
cityView ? cityView->tileX : -1,
|
||||
cityView ? cityView->tileY : -1
|
||||
);
|
||||
|
||||
// 3. Render 3D Units & Cities (Cylinders & Bastions)
|
||||
Unit *selected = GameManager::instance().getSelectedUnit();
|
||||
m_unitRenderer.renderUnits(
|
||||
GameManager::instance().getUnits(),
|
||||
@@ -2806,10 +2959,9 @@ void QSceneRenderer::paintGL()
|
||||
cityView ? cityView->tileY : -1
|
||||
);
|
||||
|
||||
// 3. Render 2D UI & HUD Overlays via QPainter
|
||||
// 4. Render 2D UI & HUD Overlays via QPainter
|
||||
QPainter painter(this);
|
||||
drawCityBorders(painter, vMatrix);
|
||||
drawRoadsOverlay(painter, vMatrix);
|
||||
drawImprovementsOverlay(painter, vMatrix);
|
||||
if (!cityView) {
|
||||
drawPathAndRange(painter, selected, vMatrix);
|
||||
|
||||
Reference in New Issue
Block a user