#pragma once #include #include #include #include #include #include #include #include "EventHandler.h" #include "BeamFiredEvent.h" #include "entt/entity/entity.hpp" #include "EntitySelectionChangedEvent.h" #include "Tick.h" #include "TickDriver.h" #include "VisualsConfig.h" class ArenaSimulation; class QPainter; class ArenaView : public QOpenGLWidget, public EventHandler { Q_OBJECT public: ArenaView(ArenaSimulation* sim, const VisualsConfig* visuals, QWidget* parent = nullptr); ~ArenaView() override; void setGameSpeed(double multiplier); double getGameSpeed() const; void togglePause(); void stopRendering(); protected: void paintGL() override; void mousePressEvent(QMouseEvent* event) override; void keyPressEvent(QKeyEvent* event) override; private slots: void onFrame(); private: void handleEvent(std::shared_ptr event) override; void drawTiles(QPainter& painter); void drawBuildings(QPainter& painter); void drawStations(QPainter& painter); void drawDebris(QPainter& painter); void drawShips(QPainter& painter); void drawDebugSensorRanges(QPainter& painter); void drawDebugTargetLines(QPainter& painter); void drawBeams(QPainter& painter); float getTilePx() const; QPointF worldToWidget(QVector2D worldPos) const; QPointF tileToWidget(QPoint tile) const; QRectF tileRect(QPoint tile) const; std::optional entityPosition(entt::entity entity) const; QVector2D widgetToWorld(QPoint widgetPt) const; struct ActiveBeam { BeamFiredEvent event; QVector2D targetOffset; }; // Beam lifetime in game ticks so beams freeze with the simulation when // paused or slowed, instead of fading on wall-clock time (REQ-SHP-FIRING-BEAM). static constexpr Tick kBeamLifetimeTicks = secondsToTicks(0.3); ArenaSimulation* m_sim; const VisualsConfig* m_visuals; TickDriver m_tickDriver; QElapsedTimer m_frameTimer; std::mt19937 m_rng; double m_gameSpeedMultiplier; double m_prevNonZeroSpeed; QTimer* m_renderTimer; std::vector m_activeBeams; bool m_finishedEmitted; std::optional m_selectedEntity; bool m_debugDraw; };