#pragma once #include #include "game_rng.h" namespace roro::games { // Pong against the device (issue #101): the player's paddle on the left, the device's on the // right, first to 7. The ball goes faster with each return, and the device's paddle only moves so // fast: a steep, fast ball gets past it. Lengths are pixels of the 240 x 122 field, times seconds. class Pong { public: static constexpr float kWidth = 240, kHeight = 122; static constexpr float kPaddleH = 24, kPaddleW = 3, kMargin = 6, kBall = 4; static constexpr float kPlayerSpeed = 150, kDeviceSpeed = 88; static constexpr float kServeSpeed = 110, kMaxSpeed = 270, kFaster = 1.06f; static constexpr float kServePause = 0.8f; static constexpr int kWinScore = 7; enum Event : uint8_t { Wall = 1, Hit = 2, Point = 4, Over = 8 }; enum class Phase : uint8_t { Serve, Play, Over }; explicit Pong(uint32_t seed) : rng_(seed) { start(); } void start(); // `seconds` later, with the player's paddle asked up (-1), down (1) or left alone (0). // What happened, as Events. uint8_t step(float seconds, int move); Phase phase() const { return phase_; } float ballX() const { return x_; } float ballY() const { return y_; } float speed() const { return speed_; } float playerY() const { return player_; } // the paddle's middle float deviceY() const { return device_; } int playerScore() const { return playerScore_; } int deviceScore() const { return deviceScore_; } bool playerWon() const { return playerScore_ >= kWinScore; } int rally() const { return rally_; } // the player's returns since the serve int longestRally() const { return longest_; } // in this game private: uint8_t tick(float dt, int move); void serve(bool toPlayer); bool meets(float paddleY) const; void bounceOff(float paddleY, bool toRight); Rng rng_; Phase phase_ = Phase::Serve; float x_ = 0, y_ = 0, vx_ = 0, vy_ = 0, speed_ = 0; float player_ = 0, device_ = 0, wait_ = 0; int playerScore_ = 0, deviceScore_ = 0, rally_ = 0, longest_ = 0; }; } // namespace roro::games