A classic Pong game developed on C# with MonoGame, built around small, testable pieces: input becomes explicit actions, a match session owns the rules, and the screens handle presentation and navigation requests.
First player to reach 10 points wins the match.
| Action | Player 1 | Player 2 |
|---|---|---|
| Move paddle | W / S |
↑ / ↓ |
| Start / pause / resume | ENTER |
ENTER |
| Open pause menu | ESC |
ESC |
In the pause menu: CONTINUE, MAIN MENU or EXIT GAME, navigating with ↑ / ↓ and confirming with ENTER.
Requires the .NET 8 SDK.
dotnet run --project HardPongThe match logic (state machine, score, physics, input mapping) is covered by unit tests that run without opening a window or loading any assets.
dotnet testHardPong/
├── Screens/ # MainMenuScreen, GameplayScreen (build, draw, navigate)
├── Gameplay/ # MatchSession, MatchScore, GameStateController, entities and controllers
├── Input/ # keyboard reading translated into GameAction
├── Physics/ # pure collision detection and the collision responses
├── Rendering/ # SpriteRenderer
├── UI/
│ ├── Menus/ # menu presentation, selection, results and selection arrow
│ ├── Effects/ # color, scale and position effects
│ └── Sprites/ # sprites and movement strategies
└── Audio/ # match audio owner
The flow is one-directional: input is read into GameActions, MatchSession executes them
and simulates frames, and the screens render the entities' state. Physics never plays sounds
and never draws.
MatchSession.SimulateFrame returns CollisionEvents for paddle hits, wall hits and points.
GameplayScreen passes these facts to PongAudio for playback and stops the score sound
when a round or match is reset. Session tests require no audio objects or audio mocks.
GameScreen separates resource loading from activation: Initialize loads content once,
Enter prepares each visit, and Leave stops playback and rearms input without releasing resources.
Entering gameplay starts a fresh match. PongGame disposes both screens at shutdown,
including the inactive screen, before MonoGame releases shared content and the graphics device.
