Implement REQ-UI-PORT-TARGET-GLYPH builder-ghost port preview
While in builder mode, draw an additional directional glyph centered in each output port's target cell (the cell just outside the footprint the port pushes into), previewing where output will flow before placement. - drawPortGlyph gains a `centered` flag so it can render either offset toward the port body's exit edge (existing on-tile glyph) or centered in a given tile (the new target cell). - drawBuildingGhost gains `showPortTargetGlyphs`, passed true only for the single-building builder ghost and false for the blueprint-placement ghost, so the preview is builder-mode only. - The Tunnel Entry is excluded — it receives items from any non-mouth edge rather than emitting into one adjacent cell. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y7N59FsLA5e2kuVdqe4Uhc
This commit is contained in:
@@ -895,25 +895,31 @@ void GameWorldView::placeAtTile(QPoint tile)
|
||||
// Port glyph helper
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void GameWorldView::drawPortGlyph(QPainter& painter, QPoint bodyTile,
|
||||
Rotation direction, const QColor& color)
|
||||
void GameWorldView::drawPortGlyph(QPainter& painter, QPoint tile,
|
||||
Rotation direction, const QColor& color,
|
||||
bool centered)
|
||||
{
|
||||
const float px = getTilePx();
|
||||
const QRectF tr = tileRect(bodyTile);
|
||||
const QRectF tr = tileRect(tile);
|
||||
const QPointF center(tr.x() + static_cast<qreal>(px) * 0.5,
|
||||
tr.y() + static_cast<qreal>(px) * 0.5);
|
||||
|
||||
QPointF offset;
|
||||
QPointF edgeOffset;
|
||||
const char* ch;
|
||||
switch (direction)
|
||||
{
|
||||
case Rotation::East: offset = QPointF(px * 0.25f, 0); ch = ">"; break;
|
||||
case Rotation::West: offset = QPointF(-px * 0.25f, 0); ch = "<"; break;
|
||||
case Rotation::North: offset = QPointF(0, -px * 0.25f); ch = "^"; break;
|
||||
case Rotation::South: offset = QPointF(0, px * 0.25f); ch = "v"; break;
|
||||
case Rotation::East: edgeOffset = QPointF(px * 0.25f, 0); ch = ">"; break;
|
||||
case Rotation::West: edgeOffset = QPointF(-px * 0.25f, 0); ch = "<"; break;
|
||||
case Rotation::North: edgeOffset = QPointF(0, -px * 0.25f); ch = "^"; break;
|
||||
case Rotation::South: edgeOffset = QPointF(0, px * 0.25f); ch = "v"; break;
|
||||
default: return;
|
||||
}
|
||||
|
||||
// Centered glyphs sit in the middle of the tile (used for a port's target
|
||||
// cell, REQ-UI-PORT-TARGET-GLYPH); otherwise offset toward the exit edge of
|
||||
// the port's body tile (REQ-UI-PORT-GLYPH).
|
||||
const QPointF offset = centered ? QPointF(0.0, 0.0) : edgeOffset;
|
||||
|
||||
const qreal half = static_cast<qreal>(px) * 0.3;
|
||||
const QPointF pos = center + offset;
|
||||
const QRectF textRect(pos.x() - half, pos.y() - half, half * 2.0, half * 2.0);
|
||||
@@ -991,7 +997,7 @@ void GameWorldView::drawBuildings(QPainter& painter)
|
||||
for (const Port& port : b.outputPorts)
|
||||
{
|
||||
drawPortGlyph(painter, portBodyTile(port.tile, port.direction),
|
||||
port.direction, bv.outline);
|
||||
port.direction, bv.outline, /*centered*/ false);
|
||||
}
|
||||
|
||||
// HP bar below the HQ footprint; the HQ's HP lives on its proxy entity.
|
||||
@@ -1070,7 +1076,8 @@ void GameWorldView::drawBuildings(QPainter& painter)
|
||||
{
|
||||
const QPoint absBody = s.anchor
|
||||
+ portBodyTile(port.tile, port.direction);
|
||||
drawPortGlyph(painter, absBody, port.direction, bv.outline);
|
||||
drawPortGlyph(painter, absBody, port.direction, bv.outline,
|
||||
/*centered*/ false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1571,7 +1578,8 @@ void GameWorldView::drawOverlays(QPainter& painter)
|
||||
if (m_builderType.has_value())
|
||||
{
|
||||
drawBuildingGhost(painter, *m_builderType, m_ghostTile,
|
||||
m_ghostRotation, m_ghostValid);
|
||||
m_ghostRotation, m_ghostValid,
|
||||
/*showPortTargetGlyphs*/ true);
|
||||
}
|
||||
|
||||
// Blueprint placement ghost
|
||||
@@ -1581,7 +1589,8 @@ void GameWorldView::drawOverlays(QPainter& painter)
|
||||
{
|
||||
const QPoint anchor = m_blueprintGhostTile + bb.offset;
|
||||
const bool valid = isValidPlacement(bb.type, anchor, bb.rotation);
|
||||
drawBuildingGhost(painter, bb.type, anchor, bb.rotation, valid);
|
||||
drawBuildingGhost(painter, bb.type, anchor, bb.rotation, valid,
|
||||
/*showPortTargetGlyphs*/ false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1634,7 +1643,7 @@ void GameWorldView::drawOverlays(QPainter& painter)
|
||||
|
||||
void GameWorldView::drawBuildingGhost(QPainter& painter, BuildingType type,
|
||||
QPoint anchorTile, Rotation rotation,
|
||||
bool valid)
|
||||
bool valid, bool showPortTargetGlyphs)
|
||||
{
|
||||
const BuildingDef* def = findBuildingDef(type);
|
||||
if (!def) { return; }
|
||||
@@ -1688,7 +1697,21 @@ void GameWorldView::drawBuildingGhost(QPainter& painter, BuildingType type,
|
||||
for (const Port& port : parsed.outputPorts)
|
||||
{
|
||||
drawPortGlyph(painter, anchorTile + portBodyTile(port.tile, port.direction),
|
||||
port.direction, lineColor);
|
||||
port.direction, lineColor, /*centered*/ false);
|
||||
}
|
||||
|
||||
// REQ-UI-PORT-TARGET-GLYPH: while in builder mode, additionally mark each
|
||||
// output port's target cell (the cell just outside the footprint the port
|
||||
// pushes into) with a directional glyph, previewing where output will flow.
|
||||
// The Tunnel Entry is excluded — it receives items from any of its non-mouth
|
||||
// edges rather than emitting into a single adjacent cell.
|
||||
if (showPortTargetGlyphs && type != BuildingType::TunnelEntry)
|
||||
{
|
||||
for (const Port& port : parsed.outputPorts)
|
||||
{
|
||||
drawPortGlyph(painter, anchorTile + port.tile, port.direction,
|
||||
lineColor, /*centered*/ true);
|
||||
}
|
||||
}
|
||||
|
||||
painter.setOpacity(1.0);
|
||||
|
||||
@@ -175,11 +175,13 @@ private:
|
||||
std::vector<BuildingId> buildingsInBox(QPoint cornerA, QPoint cornerB) const;
|
||||
QVector2D widgetToWorld(QPoint widgetPt) const;
|
||||
|
||||
void drawPortGlyph(QPainter& painter, QPoint bodyTile,
|
||||
Rotation direction, const QColor& color);
|
||||
void drawPortGlyph(QPainter& painter, QPoint tile,
|
||||
Rotation direction, const QColor& color,
|
||||
bool centered);
|
||||
|
||||
void drawBuildingGhost(QPainter& painter, BuildingType type,
|
||||
QPoint anchorTile, Rotation rotation, bool valid);
|
||||
QPoint anchorTile, Rotation rotation, bool valid,
|
||||
bool showPortTargetGlyphs);
|
||||
|
||||
void placeBlueprintAtTile(QPoint center);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user