Client Architecture Overview
This document provides a comprehensive overview of the R-Type client architecture, design patterns, and component interactions.
ποΈ High-Level Architectureβ
The R-Type client follows a layered architecture with clear separation of concerns:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Application Layer β
β (main.cpp - Game Loop) β
βββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββΌββββββββββββββ
β β β
βββββββββΌβββββββ βββββΌββββββ ββββββΌβββββββ
β UI Systems β β Network β β Game β
β (Menus) β β Client β β Renderer β
βββββββββ¬βββββββ ββββββ¬βββββ βββββββ¬ββββββ
β β β
βββββββββΌβββββββ βββββΌββββββ ββββββΌβββββββ
β Wrappers β β Asio β β SFML β
β (Interfaces) β β β β β
ββββββββββββββββ βββββββββββ βββββββββββββ
π― Core Componentsβ
1. Main Game Loop (client/main.cpp)β
The entry point that orchestrates all systems:
int main() {
// 1. Initialize configuration
Config::getInstance().load();
// 2. Create window and wrappers
auto window = std::make_unique<WindowSFML>(width, height, "R-Type");
auto graphics = std::make_unique<GraphicsSFML>(*window);
auto input = std::make_unique<InputSFML>(*window);
auto audio = std::make_unique<AudioSFML>();
// 3. Initialize systems
auto networkClient = std::make_unique<NetworkClientAsio>();
SoundManager::getInstance().loadAll();
// 4. Create UI screens
auto menu = std::make_unique<Menu>(*window, *graphics, *input);
auto settingsMenu = std::make_unique<SettingsMenu>(*window, *graphics, *input);
// ... other screens
// 5. Main game loop
GameState state = GameState::Menu;
while (window->isOpen()) {
float deltaTime = clock.restart();
// Update current state
switch (state) {
case GameState::Menu:
state = handleMenuState(...);
break;
case GameState::Playing:
state = handlePlayingState(...);
break;
// ... other states
}
// Render current state
window->clear();
renderCurrentState(state, ...);
window->display();
}
}
Responsibilities:
- Initialize all subsystems
- Manage game state transitions
- Run the main game loop
- Handle input and rendering
2. Wrapper Layerβ
Abstract interfaces that decouple game logic from SFML:
Graphics Wrapper (wrapper/graphics/)β
IGraphics- Rendering interfaceISprite- Sprite managementGraphicsSFML- SFML implementation
Window Wrapper (wrapper/window/)β
IWindow- Window managementWindowSFML- SFML implementation
Input Wrapper (wrapper/input/)β
IInput- Input handlingInputSFML- SFML implementation
Audio Wrapper (wrapper/audio/)β
IAudio- Audio playbackAudioSFML- SFML implementation
Benefits:
- β Easy to swap SFML for another library (SDL, Raylib, etc.)
- β Testable game logic (mock interfaces)
- β Clean separation of concerns
3. UI Systemsβ
Menu System (client/Menu.cpp)β
Main menu with navigation:
- Play
- Settings
- Replays
- Exit
Lobby Systemβ
LobbyMenu.cpp- Create or join lobbyLobbyConfigMenu.cpp- Configure game rulesLobbyWaitingRoom.cpp- Wait for playersJoinLobbyDialog.cpp- Join existing lobby
Settings System (client/SettingsMenu.cpp)β
Configuration UI:
- Resolution selection
- Fullscreen toggle
- Volume sliders (SFX, Music)
- Key bindings
- Color blind filters
Game Over Screen (client/GameOverScreen.cpp)β
Post-game UI:
- Final score display
- Return to menu
- Play again option
4. Network Clientβ
Purpose: Handle all client-server communication
Implementation: client/network/NetworkClientAsio.cpp
Key Features:
- UDP socket communication via Boost.Asio
- Asynchronous I/O with dedicated network thread
- Callback-based event system
- Automatic reconnection handling
Message Flow:
Client ββsendLogin()ββ> Server
Client <βLoginResponseβ Server
Client ββsendInput()ββ> Server
Client <βEntityUpdateβ Server
Client <βPositionSyncβ Server
See Network Architecture for details.
5. Game Rendererβ
Purpose: Render active gameplay
Implementation: client/src/Game.cpp
Rendering Pipeline:
1. Clear window
2. Draw background (parallax scrolling)
3. Draw entities (sprites)
4. Draw UI overlays (score, health)
5. Apply color blind filter (if enabled)
6. Display frame
Entity Rendering:
- Player ships
- Enemies
- Projectiles
- Power-ups
- Explosions (particles)
6. Configuration Systemβ
Purpose: Persist user settings
Implementation: client/Config.cpp
Storage: config.json in working directory
Managed Settings:
{
"resolutionWidth": 1920,
"resolutionHeight": 1080,
"fullscreen": 0,
"sfxVolume": 100.0,
"musicVolume": 100.0,
"colorBlindMode": "None",
"keyBindings": {
"moveUp": "Z",
"moveDown": "S",
"moveLeft": "Q",
"moveRight": "D",
"shoot": "Space"
}
}
See Configuration System for details.
7. Audio Systemβ
Purpose: Manage sound effects and music
Implementation: client/src/SoundManager.cpp
Singleton Pattern:
SoundManager& soundManager = SoundManager::getInstance();
soundManager.playSound("SHOOT");
soundManager.playMusic();
soundManager.setVolume(75.0f);
Audio Assets:
- Background music (looping)
- Sound effects (shoot, explosion, hit, UI)
See Audio System for details.
8. Replay Systemβ
Purpose: Record and playback game sessions
Components:
ReplayRecorder- Records game eventsReplayPlayer- Plays back recorded sessionsReplayBrowser- UI for selecting replaysReplayControls- Playback controls (pause, seek, speed)
File Format: .rtr (R-Type Replay)
- Binary format
- Stores timestamped game events
- Frame-perfect reproduction
See Replay System for details.
π State Managementβ
The client uses a finite state machine to manage different screens:
enum class GameState {
Menu, // Main menu
Lobby, // Lobby menu (create/join)
LobbyConfig, // Configure game rules
LobbyWaiting, // Waiting room
JoinLobbyDialog, // Join lobby dialog
Settings, // Settings menu
Playing, // Active gameplay
ReplayBrowser, // Replay selection
WatchingReplay, // Watching a replay
GameOver // Game over screen
};
State Transitions:
Menu ββ> Lobby ββ> LobbyConfig ββ> LobbyWaiting ββ> Playing ββ> GameOver
β β β β
ββββββββββΌββββββββββββββββββββββββββββββββββββββββββββΌβββββββββββββ
β β
βββ> JoinLobbyDialog ββ> LobbyWaiting ββββββ
β
βββ> Settings ββββββββββββββββββββββββββββββ
β
βββ> ReplayBrowser ββ> WatchingReplay ββββββ
See Game State Management for detailed state flow.
π¨ Design Patterns Usedβ
1. Singleton Patternβ
Used for global managers:
Config::getInstance()SoundManager::getInstance()ColorBlindFilter::getInstance()
2. Interface/Implementation Patternβ
All wrapper components:
IWindow/WindowSFMLIGraphics/GraphicsSFMLIInput/InputSFML
3. Observer Patternβ
Network callbacks:
networkClient->setOnEntitySpawnCallback([](const EntitySpawnPacket& packet) {
// Handle entity spawn
});
4. State Patternβ
Game state machine with state-specific logic
π Threading Modelβ
The client uses 2 threads:
Main Thread (Game Loop)β
- Input processing
- Game logic updates
- Rendering
- UI updates
Network Thread (Asio I/O)β
- Receiving UDP packets
- Sending UDP packets
- Message queue processing
Synchronization:
std::mutexprotects shared message queue- Callbacks executed on main thread via polling
π Component Interactionsβ
Example: Player Input Flowβ
1. User presses "Space" key
β
2. InputSFML detects key press
β
3. Main loop reads input state
β
4. NetworkClient sends C2S_INPUT packet
β
5. Server processes input
β
6. Server broadcasts entity updates
β
7. NetworkClient receives S2C_ENTITY_POS
β
8. Callback updates game state
β
9. Renderer draws updated entities
π¦ File Structureβ
client/
βββ main.cpp # Entry point
βββ CMakeLists.txt # Build configuration
β
βββ Menu.hpp/cpp # Main menu
βββ SettingsMenu.hpp/cpp # Settings screen
βββ GameOverScreen.hpp/cpp # Game over screen
β
βββ LobbyMenu.hpp/cpp # Lobby menu
βββ LobbyConfigMenu.hpp/cpp # Game rules config
βββ LobbyWaitingRoom.hpp/cpp # Waiting room
βββ JoinLobbyDialog.hpp/cpp # Join dialog
β
βββ ReplayBrowser.hpp/cpp # Replay browser
βββ ReplayControls.hpp/cpp # Playback controls
β
βββ Config.hpp/cpp # Configuration system
βββ Button.hpp/cpp # Button UI component
βββ InputField.hpp/cpp # Text input component
βββ Slider.hpp/cpp # Slider UI component
βββ ToggleButton.hpp/cpp # Toggle UI component
βββ ColorBlindFilter.hpp/cpp # Accessibility filters
βββ KeyBinding.hpp/cpp # Key binding system
β
βββ network/
β βββ NetworkClientAsio.hpp/cpp # Network client
β βββ ClientGameState.hpp/cpp # Game state sync
β
βββ src/
β βββ Game.hpp/cpp # Game renderer
β βββ Background.hpp/cpp # Background rendering
β βββ SoundManager.hpp/cpp # Audio manager
β βββ ReplayRecorder.hpp/cpp # Replay recording
β βββ ReplayViewer.hpp/cpp # Replay playback
β
βββ wrapper/
βββ graphics/
β βββ Graphics.hpp # IGraphics interface
β βββ GraphicsSFML.hpp/cpp # SFML graphics
β βββ Sprite.hpp # ISprite interface
β βββ SpriteSFML.hpp/cpp # SFML sprite
βββ window/
β βββ Window.hpp # IWindow interface
β βββ WindowSFML.hpp/cpp # SFML window
βββ input/
β βββ Input.hpp # IInput interface
β βββ InputSFML.hpp/cpp # SFML input
βββ audio/
βββ Audio.hpp # IAudio interface
βββ AudioSFML.hpp/cpp # SFML audio
π Performance Considerationsβ
Renderingβ
- Target: 60 FPS
- VSync: Enabled by default
- Frame limiting:
window->setFramerateLimit(60)
Networkingβ
- Protocol: UDP (low latency)
- Update rate: Server sends ~20 updates/sec
- Client prediction: Smooth interpolation between updates
Memoryβ
- Texture caching: Sprites reuse loaded textures
- Object pooling: Reuse projectile/enemy entities
- Smart pointers:
std::unique_ptrfor RAII
π§ Build Configurationβ
# client/CMakeLists.txt
add_executable(r-type_client
main.cpp
Menu.cpp
SettingsMenu.cpp
# ... all client sources
)
target_link_libraries(r-type_client PRIVATE
sfml-graphics
sfml-window
sfml-system
sfml-audio
Boost::asio
common # Shared network protocol
)
π Further Readingβ
- UI Systems - Detailed UI documentation
- Game State Management - State machine details
- Network Architecture - Networking guide
- SFML Wrapper - Wrapper interfaces
- Tutorials - Hands-on guides
π€ Common Questionsβ
Q: Why use wrappers instead of SFML directly? A: Wrappers provide library independence, easier testing, and cleaner interfaces.
Q: How does the client handle disconnections? A: The network client detects timeouts and attempts automatic reconnection.
Q: Can I add new menu screens? A: Yes! See the Tutorials for a step-by-step guide.
Q: Where are textures and sounds loaded? A: Assets are loaded on-demand when screens are created or during game initialization.