draw beam wider at the source than at the target

This commit is contained in:
2026-07-14 21:52:05 +02:00
parent 76812ba0c5
commit d465671cfc

View File

@@ -15,11 +15,13 @@
#include <QDir>
#include <QFont>
#include <QKeyEvent>
#include <QLinearGradient>
#include <QMessageBox>
#include <QMouseEvent>
#include <QPainter>
#include <QPen>
#include <QPolygonF>
#include <QRadialGradient>
#include <QRegion>
#include <QStringList>
#include <QTimer>
@@ -1487,6 +1489,9 @@ void GameWorldView::drawDebugOverlay(QPainter& painter)
void GameWorldView::drawBeams(QPainter& painter)
{
const QPainter::RenderHints savedHints = painter.renderHints();
painter.setRenderHint(QPainter::Antialiasing, true);
for (const ActiveBeam& beam : m_activeBeams)
{
const std::optional<QVector2D> shooterPos = entityPosition(beam.event.shooter);
@@ -1500,10 +1505,55 @@ void GameWorldView::drawBeams(QPainter& painter)
case BeamKind::Repair: color = m_visuals->beams.repairColor; break;
case BeamKind::Salvage: color = m_visuals->beams.salvageColor; break;
}
painter.setPen(QPen(color, m_visuals->beams.widthPx));
painter.drawLine(worldToWidget(*shooterPos),
worldToWidget(*targetPos + beam.targetOffset));
const QPointF s = worldToWidget(*shooterPos);
const QPointF t = worldToWidget(*targetPos + beam.targetOffset);
// Unit direction/perpendicular of the beam in widget space. A degenerate
// zero-length beam (shooter and target coincide) has no direction to
// taper along, so skip it.
const QVector2D delta(static_cast<float>(t.x() - s.x()),
static_cast<float>(t.y() - s.y()));
const float lengthPx = delta.length();
if (lengthPx < 0.001f) { continue; }
const QVector2D dir = delta / lengthPx;
const QVector2D perp(-dir.y(), dir.x());
// Directional taper: draw the beam as a quad that is wide at the shooter
// and narrows to a faint tip at the target, so it reads as an arrow
// pointing away from whoever fired it. Without this, a beam strung
// between two nearby ships is symmetric and gives no cue which end is the
// source (the readability problem this addresses).
const float widthPx = std::max(1.0f, static_cast<float>(m_visuals->beams.widthPx));
const float baseHalf = widthPx * 1.f;
const float tipHalf = widthPx * 0.35f;
QPolygonF quad;
quad << QPointF(s.x() + static_cast<qreal>(perp.x() * baseHalf),
s.y() + static_cast<qreal>(perp.y() * baseHalf))
<< QPointF(s.x() - static_cast<qreal>(perp.x() * baseHalf),
s.y() - static_cast<qreal>(perp.y() * baseHalf))
<< QPointF(t.x() - static_cast<qreal>(perp.x() * tipHalf),
t.y() - static_cast<qreal>(perp.y() * tipHalf))
<< QPointF(t.x() + static_cast<qreal>(perp.x() * tipHalf),
t.y() + static_cast<qreal>(perp.y() * tipHalf));
QColor bright = color;
bright.setAlpha(255);
QColor faint = color;
faint.setAlpha(90);
QLinearGradient bodyGrad(s, t);
bodyGrad.setColorAt(0.0, bright);
bodyGrad.setColorAt(1.0, faint);
painter.setPen(Qt::NoPen);
painter.setBrush(bodyGrad);
painter.drawPolygon(quad);
}
painter.setBrush(Qt::NoBrush);
painter.setRenderHints(savedHints);
}
void GameWorldView::drawOverlays(QPainter& painter)