Panel hit detection but broken available games, thats enough for tonight
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QPainterPath>
|
#include <QPainterPath>
|
||||||
|
#include <QTimer>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QtMath>
|
#include <QtMath>
|
||||||
|
|
||||||
@@ -24,6 +25,7 @@ void PanelsPanel::setRnpCount(int count)
|
|||||||
{
|
{
|
||||||
m_count = count;
|
m_count = count;
|
||||||
m_colors.clear();
|
m_colors.clear();
|
||||||
|
m_hits.clear();
|
||||||
m_statusLabel->setText(count > 0
|
m_statusLabel->setText(count > 0
|
||||||
? QString("%1 panel%2").arg(count).arg(count == 1 ? "" : "s")
|
? QString("%1 panel%2").arg(count).arg(count == 1 ? "" : "s")
|
||||||
: "No panels reported");
|
: "No panels reported");
|
||||||
@@ -36,10 +38,21 @@ void PanelsPanel::setPanelColor(int index, const QColor &color)
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PanelsPanel::impactPanel(int index, int power)
|
||||||
|
{
|
||||||
|
m_hits[index] = power;
|
||||||
|
update();
|
||||||
|
QTimer::singleShot(3000, this, [this, index]() {
|
||||||
|
m_hits.remove(index);
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void PanelsPanel::reset()
|
void PanelsPanel::reset()
|
||||||
{
|
{
|
||||||
m_count = 0;
|
m_count = 0;
|
||||||
m_colors.clear();
|
m_colors.clear();
|
||||||
|
m_hits.clear();
|
||||||
m_statusLabel->setText("Connect to load panels...");
|
m_statusLabel->setText("Connect to load panels...");
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
@@ -59,44 +72,84 @@ void PanelsPanel::paintEvent(QPaintEvent *)
|
|||||||
const double outerR = side / 2.0;
|
const double outerR = side / 2.0;
|
||||||
const double innerR = outerR * 0.44;
|
const double innerR = outerR * 0.44;
|
||||||
|
|
||||||
const QRectF outerRect(cx - outerR, cy - outerR, side, side);
|
const QRectF outerRect(cx - outerR, cy - outerR, side, side);
|
||||||
const QRectF innerRect(cx - innerR, cy - innerR, innerR * 2, innerR * 2);
|
const QRectF innerRect(cx - innerR, cy - innerR, innerR * 2, innerR * 2);
|
||||||
|
|
||||||
const double gapDeg = (m_count > 1) ? 3.0 : 0.0;
|
const double gapDeg = (m_count > 1) ? 3.0 : 0.0;
|
||||||
const double segSpan = (360.0 - m_count * gapDeg) / m_count;
|
const double segSpan = (360.0 - m_count * gapDeg) / m_count;
|
||||||
|
|
||||||
static const QColor kDefault(100, 140, 180);
|
static const QColor kDefault(100, 140, 180);
|
||||||
|
static const QColor kHit(220, 40, 40);
|
||||||
|
|
||||||
for (int i = 0; i < m_count; ++i) {
|
for (int i = 0; i < m_count; ++i) {
|
||||||
|
const bool isHit = m_hits.contains(i);
|
||||||
const double startAngle = 90.0 - i * (segSpan + gapDeg);
|
const double startAngle = 90.0 - i * (segSpan + gapDeg);
|
||||||
const double sweep = -segSpan;
|
const double sweep = -segSpan;
|
||||||
|
|
||||||
|
// --- Segment path ---
|
||||||
QPainterPath path;
|
QPainterPath path;
|
||||||
path.arcMoveTo(outerRect, startAngle);
|
path.arcMoveTo(outerRect, startAngle);
|
||||||
path.arcTo(outerRect, startAngle, sweep);
|
path.arcTo(outerRect, startAngle, sweep);
|
||||||
path.arcTo(innerRect, startAngle + sweep, -sweep);
|
path.arcTo(innerRect, startAngle + sweep, -sweep);
|
||||||
path.closeSubpath();
|
path.closeSubpath();
|
||||||
|
|
||||||
p.setBrush(m_colors.value(i, kDefault));
|
QColor segColor = isHit ? kHit : m_colors.value(i, kDefault);
|
||||||
p.setPen(QPen(Qt::white, 2));
|
p.setBrush(segColor);
|
||||||
|
p.setPen(QPen(Qt::white, isHit ? 3 : 2));
|
||||||
p.drawPath(path);
|
p.drawPath(path);
|
||||||
|
|
||||||
// Label at segment midpoint
|
// --- Midpoint for label / hit circle ---
|
||||||
const double midAngle = startAngle + sweep / 2.0;
|
const double midAngle = startAngle + sweep / 2.0;
|
||||||
const double midAngleRad = qDegreesToRadians(midAngle);
|
const double midAngleRad = qDegreesToRadians(midAngle);
|
||||||
const double midR = (outerR + innerR) / 2.0;
|
const double midR = (outerR + innerR) / 2.0;
|
||||||
const QPointF tc(cx + midR * qCos(midAngleRad),
|
const QPointF mid(cx + midR * qCos(midAngleRad),
|
||||||
cy - midR * qSin(midAngleRad));
|
cy - midR * qSin(midAngleRad));
|
||||||
|
|
||||||
QFont font = p.font();
|
if (isHit) {
|
||||||
font.setBold(true);
|
// ---- Red glow halo ring around segment ----
|
||||||
font.setPointSize(qMax(7, qMin(12, static_cast<int>(outerR / (m_count * 0.55 + 2)))));
|
QPen haloPen(QColor(255, 80, 80, 120), 6);
|
||||||
p.setFont(font);
|
p.setBrush(Qt::NoBrush);
|
||||||
p.setPen(Qt::white);
|
p.setPen(haloPen);
|
||||||
p.drawText(QRectF(tc.x() - 22, tc.y() - 11, 44, 22), Qt::AlignCenter, QString::number(i));
|
p.drawPath(path);
|
||||||
|
|
||||||
|
// ---- Red filled circle centred on segment ----
|
||||||
|
const double circR = qMin(outerR - innerR, midR * 0.38) * 0.9;
|
||||||
|
const QRectF circRect(mid.x() - circR, mid.y() - circR, circR * 2, circR * 2);
|
||||||
|
|
||||||
|
// drop shadow
|
||||||
|
p.setBrush(QColor(0, 0, 0, 60));
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.drawEllipse(circRect.adjusted(2, 3, 2, 3));
|
||||||
|
|
||||||
|
// circle fill: radial gradient (bright centre → dark red)
|
||||||
|
QRadialGradient grad(mid, circR, QPointF(mid.x() - circR*0.3, mid.y() - circR*0.3));
|
||||||
|
grad.setColorAt(0.0, QColor(255, 100, 100));
|
||||||
|
grad.setColorAt(1.0, QColor(160, 10, 10));
|
||||||
|
p.setBrush(grad);
|
||||||
|
p.setPen(QPen(QColor(255, 200, 200), 1.5));
|
||||||
|
p.drawEllipse(circRect);
|
||||||
|
|
||||||
|
// power value text
|
||||||
|
QFont pf = p.font();
|
||||||
|
pf.setBold(true);
|
||||||
|
pf.setPointSize(qMax(6, qMin(11, static_cast<int>(circR * 0.72))));
|
||||||
|
p.setFont(pf);
|
||||||
|
p.setPen(Qt::white);
|
||||||
|
p.drawText(circRect, Qt::AlignCenter, QString::number(m_hits[i]));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// ---- Normal index label ----
|
||||||
|
QFont font = p.font();
|
||||||
|
font.setBold(true);
|
||||||
|
font.setPointSize(qMax(7, qMin(12, static_cast<int>(outerR / (m_count * 0.55 + 2)))));
|
||||||
|
p.setFont(font);
|
||||||
|
p.setPen(Qt::white);
|
||||||
|
p.drawText(QRectF(mid.x() - 22, mid.y() - 11, 44, 22),
|
||||||
|
Qt::AlignCenter, QString::number(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Centre hole: total count
|
// --- Centre hole: total count ---
|
||||||
QFont cf = p.font();
|
QFont cf = p.font();
|
||||||
cf.setBold(true);
|
cf.setBold(true);
|
||||||
cf.setPointSize(qMax(8, static_cast<int>(innerR * 0.45)));
|
cf.setPointSize(qMax(8, static_cast<int>(innerR * 0.45)));
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ public:
|
|||||||
|
|
||||||
void setRnpCount(int count);
|
void setRnpCount(int count);
|
||||||
void setPanelColor(int index, const QColor &color);
|
void setPanelColor(int index, const QColor &color);
|
||||||
|
void impactPanel(int index, int power);
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -21,5 +22,6 @@ protected:
|
|||||||
private:
|
private:
|
||||||
int m_count = 0;
|
int m_count = 0;
|
||||||
QMap<int,QColor> m_colors;
|
QMap<int,QColor> m_colors;
|
||||||
|
QMap<int,int> m_hits; // panel index → impact power (active for 3 s)
|
||||||
QLabel *m_statusLabel = nullptr;
|
QLabel *m_statusLabel = nullptr;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -176,6 +176,17 @@ void WebSocketController::handleProtocol(const QString &msg)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- IMP (panel impact) ----
|
||||||
|
// Format: IMP <panel_idx> <power> <x> <y> <z>
|
||||||
|
if (cmd == "IMP" && tokens.size() >= 3) {
|
||||||
|
bool idxOk = false, pwrOk = false;
|
||||||
|
const int idx = tokens[1].toInt(&idxOk);
|
||||||
|
const int power = tokens[2].toInt(&pwrOk);
|
||||||
|
if (idxOk && pwrOk && m_panelsPanel)
|
||||||
|
m_panelsPanel->impactPanel(idx, power);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// ---- GAM listall ----
|
// ---- GAM listall ----
|
||||||
if (cmd == "GAM" && tokens.size() >= 2 && tokens[1] == "listall") {
|
if (cmd == "GAM" && tokens.size() >= 2 && tokens[1] == "listall") {
|
||||||
if (m_gamesPanel) m_gamesPanel->loadAllFromResponse(msg);
|
if (m_gamesPanel) m_gamesPanel->loadAllFromResponse(msg);
|
||||||
|
|||||||
Reference in New Issue
Block a user