Overview
Wizard Duel is built using C++17 with raylib for graphics and ENet for networking. The game follows a state-based architecture with a single main loop handling all game states, rendering, and network operations.Game states
The game uses a string-based state system stored in thestate variable:
MENU - Main menu state
MENU - Main menu state
SINGLE - Singleplayer mode
SINGLE - Singleplayer mode
Local gameplay with AI opponent. Features:
- Full game mechanics (movement, spells, health/mana)
- Camera following local player
- Collision detection with trees
- Death and respawn system
HOST - Server hosting state
HOST - Server hosting state
Transitional state for creating a game server:
- Calls
SetupHost()to initialize ENet server - Waits for
ENET_EVENT_TYPE_CONNECTevent - Transitions to
MULTIPLAYERwhen client connects - Displays “Waiting for player to join” message
JOIN - Client connection state
JOIN - Client connection state
Transitional state for joining a hosted game:
- Calls
SetupClient()to connect to server - Monitors connection status via
enet_host_service - Transitions to
MULTIPLAYERon successful connection - Shows “Connecting to host…” status
MULTIPLAYER - Online gameplay
MULTIPLAYER - Online gameplay
Full networked gameplay with position synchronization:
- Sends
PositionPacketwhen local player moves - Receives and applies opponent position updates
- Displays ping/latency information
- Handles both client and server network events
Main game loop
The game runs at 60 FPS (set viaSetTargetFPS(60)) with a single while loop:
The game loop structure places input handling before rendering, with state-specific logic contained in if-else blocks within the main loop.
Camera system
The game uses raylib’sCamera2D for world-space rendering:
Key camera features
Dynamic tracking: Camera target updates each frame to follow the local player:Asset loading system
Assets are loaded at startup and unloaded before window close:Character system
TheCharacter struct manages player state:
std::vector<Character> all_players with index 0 always being the local player.
Spell system
Spells are represented by theBall struct:
Spell types
- KEY_ONE: Blood spell (red, slow, large radius, 35.0f radius, 2.0f speed)
- KEY_TWO: Arcane spell (blue, fast, small radius, 25.0f radius, 4.0f speed)
ball_r -= 0.1f per frame).
Collision detection
Two main collision systems: Player-tree collision:CheckCollisionCircleRec to detect spell impacts, reducing tree positions to on destruction.
World generation
The game world is procedurally generated:- Map size: 2000x2000 units
- Trees: 115 randomly placed trees using
std::mt19937random generation - Boundary checking: Players take damage when leaving map bounds (x/y < 0 or > 2000)
Performance target
The game targets 60 FPS using raylib’s frame limiting:All movement and spell speeds are frame-dependent, making the 60 FPS target critical for gameplay consistency.