Aller au contenu

Architecture Client

Le client R-Type utilise une architecture Scene-based avec plugins graphiques.

Vue d'Ensemble

flowchart TB
    subgraph Engine
        Loop[Game Loop]
        SM[Scene Manager]
        Events[Event System]
    end

    subgraph Scenes
        Menu[MenuScene]
        Lobby[LobbyScene]
        Game[GameScene]
    end

    subgraph Systems
        GFX[Graphics Plugin]
        NET[Network Client]
        Audio[Audio Manager]
    end

    Loop --> SM
    SM --> Menu
    SM --> Lobby
    SM --> Game
    Loop --> Events
    Game --> GFX
    Game --> NET
    Game --> Audio

    style Loop fill:#7c3aed,color:#fff

Scene System

Interface IScene

// src/client/include/scenes/IScene.hpp
struct GameContext {
    std::shared_ptr<graphics::IWindow> window;
    std::shared_ptr<client::network::UDPClient> udpClient;
    std::shared_ptr<client::network::TCPClient> tcpClient;
    std::string sessionToken;
};

class IScene {
public:
    virtual ~IScene() = default;

    virtual void handleEvent(const events::Event& event) = 0;
    virtual void update(float deltatime) = 0;
    virtual void render() = 0;

    void setSceneManager(SceneManager* manager) { _sceneManager = manager; }
    void setContext(const GameContext& ctx) { _context = ctx; }

protected:
    SceneManager* _sceneManager = nullptr;
    GameContext _context;
};

Scene Manager

// Gère la scène courante et les transitions
class SceneManager {
    std::unique_ptr<IScene> _currentScene;
    std::unique_ptr<IScene> _nextScene;
    GameContext _context;

public:
    void setContext(const GameContext& ctx) { _context = ctx; }

    template<typename T, typename... Args>
    void changeScene(Args&&... args) {
        _nextScene = std::make_unique<T>(std::forward<Args>(args)...);
        _nextScene->setSceneManager(this);
        _nextScene->setContext(_context);
    }

    void update(float dt) {
        if (_nextScene) {
            _currentScene = std::move(_nextScene);
        }
        if (_currentScene) {
            _currentScene->update(dt);
        }
    }

    void handleEvent(const events::Event& event) {
        if (_currentScene)
            _currentScene->handleEvent(event);
    }

    void render() {
        if (_currentScene)
            _currentScene->render();
    }
};

Scenes du Jeu

stateDiagram-v2
    [*] --> ConnectionScene
    ConnectionScene --> LoginScene: Connected
    LoginScene --> MenuScene: Authenticated
    MenuScene --> LobbyScene: Create/Join Room
    MenuScene --> SettingsScene: Options
    MenuScene --> LeaderboardScene: Leaderboard
    MenuScene --> RoomBrowserScene: Browse Rooms
    LobbyScene --> GameScene: Start Game
    GameScene --> LobbyScene: Game Over
    RoomBrowserScene --> LobbyScene: Join

Game Loop

class Engine {
    SceneManager scenes_;
    IGraphicsBackend& graphics_;
    NetworkClient& network_;
    AudioManager& audio_;
    Clock clock_;
    bool running_ = true;

public:
    void run() {
        while (running_) {
            float dt = clock_.restart();

            // 1. Events
            Event event;
            while (graphics_.getWindow().pollEvent(event)) {
                if (event.type == EventType::Closed)
                    running_ = false;
                scenes_.handleEvent(event);
            }

            // 2. Network
            network_.poll();

            // 3. Update
            scenes_.update(dt);

            // 4. Render
            graphics_.clear();
            scenes_.render();
            graphics_.present();
        }
    }
};

Event System

Système d'événements type-safe avec std::variant :

// Event types
struct KeyEvent { KeyCode key; bool pressed; };
struct MouseEvent { int x, y; };
struct NetworkEvent { PacketType type; Packet data; };
struct GameEvent { std::string name; };

using Event = std::variant<
    KeyEvent,
    MouseEvent,
    NetworkEvent,
    GameEvent
>;

// Event handler
class EventDispatcher {
public:
    template<typename T, typename Handler>
    void on(Handler&& handler) {
        handlers_[typeid(T).hash_code()] =
            [h = std::forward<Handler>(handler)](const Event& e) {
                h(std::get<T>(e));
            };
    }

    void dispatch(const Event& event) {
        std::visit([this](auto&& e) {
            auto it = handlers_.find(typeid(e).hash_code());
            if (it != handlers_.end())
                it->second(event);
        }, event);
    }
};

Plugin System (Graphics)

Les backends graphiques sont chargés dynamiquement via dlopen (Linux) / LoadLibrary (Windows).

Interface IGraphicPlugin

// src/client/include/graphics/IGraphicPlugin.hpp
class IGraphicPlugin {
public:
    virtual ~IGraphicPlugin() = default;
    virtual const char* getName() const = 0;
    virtual std::shared_ptr<IWindow> createWindow(Vec2u size, const std::string& name) = 0;
    virtual std::shared_ptr<IRenderer> createRenderer(std::shared_ptr<IWindow> window) = 0;
};

// Fonctions exportées par chaque plugin
typedef IGraphicPlugin* (*create_t)();
typedef void (*destroy_t)(IGraphicPlugin*);

DynamicLib (Cross-Platform Loader)

// src/client/include/core/DynamicLib.hpp
class DynamicLib {
public:
    IGraphicPlugin* openGraphicLib(const std::string& libName);
    void destroyGraphicLib(IGraphicPlugin* graphLib);
private:
    LibHandle _handle;  // HMODULE (Win) ou void* (Linux)
    create_t _create_lib;
    destroy_t _destroy_lib;
};

// Utilisation
#ifdef _WIN32
    _handle = LoadLibraryA(libName.c_str());
    _create_lib = (create_t)GetProcAddress(_handle, "create");
#else
    _handle = dlopen(libName.c_str(), RTLD_LAZY);
    _create_lib = (create_t)dlsym(_handle, "create");
#endif

Plugins Disponibles

Plugin Bibliothèque Fichier
SFML librtype_sfml.so lib/sfml/src/SFMLPlugin.cpp
SDL2 librtype_sdl2.so lib/sdl2/src/SDL2Plugin.cpp

Structure des Dossiers

src/client/
├── main.cpp
├── include/
│   ├── scenes/
│   │   ├── IScene.hpp
│   │   ├── SceneManager.hpp
│   │   ├── MenuScene.hpp
│   │   ├── LobbyScene.hpp
│   │   └── GameScene.hpp
│   ├── graphics/
│   │   ├── IWindow.hpp
│   │   ├── IDrawable.hpp
│   │   └── IGraphicPlugin.hpp   # Interface plugin
│   ├── network/
│   │   ├── TCPClient.hpp
│   │   └── UDPClient.hpp
│   ├── audio/
│   │   ├── AudioManager.hpp
│   │   ├── VoiceChatManager.hpp
│   │   └── OpusCodec.hpp
│   ├── events/
│   │   └── Event.hpp
│   └── core/
│       ├── Engine.hpp
│       ├── GameLoop.hpp
│       └── DynamicLib.hpp       # Loader dlopen/LoadLibrary
├── src/                  # Implémentations
└── lib/                  # Plugins graphiques (.so/.dll)
    ├── sfml/
    │   ├── include/
    │   │   └── SFMLWindow.hpp
    │   └── src/
    │       └── SFMLPlugin.cpp   # Exporte create()/destroy()
    └── sdl2/
        ├── include/
        │   └── SDL2Window.hpp
        └── src/
            └── SDL2Plugin.cpp   # Exporte create()/destroy()