Networked 2-player Arkanoid built in C++17 with an authoritative server, two graphical clients, and a shared protocol layer.
Two players face each other across a field of destructible blocks. Player 1 controls the bottom paddle, Player 2 controls the top paddle. A ball bounces between the paddles; hitting a block destroys it and awards points to the player who last touched the ball. If the ball escapes past a paddle, the opponent scores. The match ends when all blocks are destroyed.
- Field: 800 x 600
- 10 x 4 grid of blocks in the center
- Block hit: +10 points
- Ball miss: +50 points for the opponent
- Paddle control: mouse position
┌──────────────────────┐ ┌──────────────────────┐
│ Server │◄──TCP──►│ Client │
│ │ │ │
│ Accept thread │ │ sf::RenderWindow │
│ Game loop (60 Hz) │ │ Mouse input │
│ State broadcast │ │ Non-blocking recv │
│ (30 Hz) │ │ │
│ ┌────────────────┐ │ │ Renders: │
│ │ Match │ │ state │ ball, paddles, │
│ │ └─ GameState │──┼────────►│ blocks, scores, │
│ │ └─ Physics │ │ │ connection status │
│ └────────────────┘ │ └──────────────────────┘
│ Leaderboard (file) │◄─input── PaddleInput
└──────────────────────┘
The server is the single source of truth. Clients send paddle input and render whatever state the server broadcasts. No client-side prediction.
| Directory | Library / Executable | Purpose |
|---|---|---|
shared/types/ |
lib shared |
Game types (Ball, Paddle, Block, GameSnapshot), constants |
shared/protocol/ |
lib shared |
Message structs, sf::Packet serialization |
game/ |
lib game_logic |
GameState (authoritative update loop), collision physics |
server/ |
exe arkanoid_server |
TCP accept thread, match lifecycle, leaderboard |
client/ |
exe arkanoid_client |
TCP client, SFML 2D renderer, input handling |
tests/ |
test executables | Protocol round-trip and game-state unit tests |
docs/ |
— | Protocol specification |
TCP with sf::Packet (length-prefixed, endian-safe).
| Direction | Message | Purpose |
|---|---|---|
| C → S | JoinRequest |
Join or reconnect (name + session token) |
| C → S | PaddleInput |
Current paddle X position |
| C → S | LeaveMatch |
Graceful disconnect |
| S → C | JoinResponse |
Accept/reject with player ID and token |
| S → C | WaitingForOpponent |
Waiting for second player |
| S → C | MatchStarting |
Initial game snapshot |
| S → C | StateUpdate |
Periodic game snapshot (30 Hz) |
| S → C | MatchEnd |
Final scores and winner |
| S → C | PlayerDisconnected |
Opponent dropped |
| S → C | PlayerReconnected |
Opponent returned |
Full protocol details: docs/protocol.md
Each player receives a session token on join. If a client disconnects, the match pauses for up to 30 seconds. Reconnecting with the same token restores the player to their slot without duplication, and the match resumes.
Match results are appended to leaderboard.txt (pipe-delimited) with player
names, scores, winner, and timestamp. The server prints the leaderboard on
startup and after each match.
- C++17, CMake 3.20+
- SFML 2.6.1 — graphics, windowing, networking (fetched automatically via CMake FetchContent)
- No other external dependencies
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --config ReleaseOn Windows, copy the SFML DLLs next to the executables:
copy build\_deps\sfml-build\lib\Release\*.dll build\server\Release\
copy build\_deps\sfml-build\lib\Release\*.dll build\client\Release\cd build
ctest --build-config Release --output-on-failurebuild/server/Release/arkanoid_server[.exe]
# or with a custom port:
build/server/Release/arkanoid_server 12345# Terminal A
build/client/Release/arkanoid_client 127.0.0.1 54321 Alice
# Terminal B
build/client/Release/arkanoid_client 127.0.0.1 54321 BobArguments: <host> <port> <player_name> [session_token]
The match starts automatically when both players connect. Control your paddle with the mouse.
- Note the session token in the server log (e.g.
token=a1b2c3...). - Close one client.
- Server logs the disconnect; match pauses.
- Relaunch the client with the token as the 4th argument:
build/client/Release/arkanoid_client 127.0.0.1 54321 Alice a1b2c3...- Server logs the reconnect; match resumes.
After a match completes, results are saved to leaderboard.txt in the
server's working directory and printed to the console.
CMakeLists.txt Root build (FetchContent for SFML)
shared/
types/constants.h Game constants
types/game_types.h Ball, Paddle, Block, GameSnapshot
protocol/message_types.h MessageType enum
protocol/messages.h Message structs + serialization
protocol/messages.cpp sf::Packet << >> implementations
game/
game_state.h / .cpp Authoritative game state
physics.h / .cpp Collision detection
server/
server.h / .cpp TCP server, accept thread, game loop
match.h / .cpp Match lifecycle, pause/resume
leaderboard.h / .cpp File-based score storage
main.cpp Entry point
client/
client_network.h / .cpp TCP client, message polling
renderer.h / .cpp SFML 2D rendering
main.cpp Entry point, input loop
tests/
test_protocol.cpp Protocol serialization round-trip
test_game_state.cpp Game state initialization and update
docs/
protocol.md Full protocol specification