Architecture du Core ARCADE

Comprendre le cœur du système et sa structure modulaire

Vue d'ensemble

Le cœur du système ARCADE est conçu autour d'un principe de modularité et de chargement dynamique. Cette architecture permet de charger et décharger des bibliothèques graphiques et des jeux à l'exécution, sans avoir à recompiler le programme principal.

Architecture ARCADE

Diagramme d'architecture du système ARCADE

Composants principaux

ArcadeCore

Le composant central qui gère tout le système. Il est responsable de:

  • Détecter et charger les bibliothèques disponibles
  • Gérer les états du programme (menu, jeu, game over)
  • Intercepter et acheminer les entrées utilisateur
  • Basculer entre les différentes bibliothèques graphiques et jeux
  • Maintenir les scores
class ArcadeCore {
public:
    ArcadeCore(const std::string &graphicLibPath);
    ~ArcadeCore();

    void run();

private:
    // États du core
    enum class CoreState {
        MENU,
        GAME,
        GAME_OVER,
        EXIT
    };

    // Méthodes principales
    void loadLibraries();
    void displayMenu();
    void handleMenuInputs();
    void updateGame();
    void renderGame();
    
    // Autres membres et méthodes...
};

DLLoader

Le chargeur de bibliothèques dynamiques qui encapsule les fonctions dlopen, dlsym, dlclose pour:

  • Charger les bibliothèques dynamiques au runtime
  • Récupérer les symboles depuis les bibliothèques
  • Instancier les modules (graphiques ou jeux)
  • Décharger proprement les bibliothèques
template
class DLLoaderImpl {
public:
    DLLoaderImpl();
    ~DLLoaderImpl();

    bool load(const std::string &path);
    void unload();
    T *getInstance();

private:
    void *_handle;
    T *_instance;
    // Autres membres...
};

EventManager

Gestionnaire d'événements qui:

  • Capture les entrées utilisateur (clavier, souris)
  • Les traduit en événements génériques pour les modules
  • Gère l'état des touches (pressée/relâchée)

ScoreManager

Gestionnaire de scores qui:

  • Enregistre et charge les meilleurs scores
  • Trie et affiche les scores par jeu
  • Persiste les données entre les sessions

Interfaces principales

IDisplayModule

Interface pour les bibliothèques graphiques qui définit:

  • L'initialisation et la fermeture de la fenêtre
  • Le rendu des éléments graphiques
  • La gestion des entrées spécifiques à la bibliothèque
class IDisplayModule {
public:
    virtual ~IDisplayModule() = default;

    virtual bool init() = 0;
    virtual void close() = 0;
    virtual void clear() = 0;
    virtual void display() = 0;
    
    virtual bool isOpen() const = 0;
    virtual void drawText(const std::string &text, int x, int y, 
                       Color color = Color::White) = 0;
    virtual void drawShape(int x, int y, int width, int height, 
                        Color color = Color::White) = 0;
    // Autres méthodes...
};

IGameModule

Interface pour les modules de jeu qui définit:

  • L'initialisation et la réinitialisation du jeu
  • La mise à jour de la logique du jeu
  • Le rendu des éléments spécifiques au jeu
  • La gestion des entrées du joueur
class IGameModule {
public:
    virtual ~IGameModule() = default;

    virtual bool init() = 0;
    virtual void reset() = 0;
    virtual void update(float dt) = 0;
    virtual void render(IDisplayModule *display) = 0;
    virtual void handleEvent(const Event &event) = 0;
    
    virtual bool isGameOver() const = 0;
    virtual int getScore() const = 0;
    // Autres méthodes...
};

Machine à états

Le core ARCADE fonctionne comme une machine à états avec les états suivants:

Machine à états

Diagramme de la machine à états du Core

MENU

État initial où l'utilisateur peut sélectionner un jeu, une bibliothèque graphique et entrer son nom. Les principales fonctions associées sont displayMenu() et handleMenuInputs().

GAME

État actif pendant le jeu. Les principales fonctions associées sont updateGame() et renderGame(). Des touches spéciales permettent de changer de bibliothèque ou de jeu en cours de partie.

GAME_OVER

État atteint lorsque la partie est terminée. Affiche le score final et propose de rejouer ou de retourner au menu. Les principales fonctions sont displayGameOver() et handleGameOverInputs().

EXIT

État de sortie qui provoque la fin de la boucle principale et ferme proprement l'application.

Flux d'exécution

Flux d'exécution

Diagramme du flux d'exécution

  1. Démarrage: Le programme principal charge la bibliothèque graphique initiale spécifiée en argument.
  2. Initialisation: ArcadeCore détecte et charge les bibliothèques disponibles dans les répertoires ./lib/.
  3. Menu principal: Affichage du menu permettant la sélection d'un jeu et la saisie du nom du joueur.
  4. Boucle de jeu: Une fois le jeu sélectionné, la boucle principale alterne entre:
    • Gestion des entrées avec handleGameInputs()
    • Mise à jour de la logique du jeu avec updateGame()
    • Rendu des éléments graphiques avec renderGame()
  5. Fin de partie: Lorsque le jeu se termine, affichage de l'écran de fin avec le score et les options.
  6. Nettoyage: À la sortie du programme, déchargement propre des bibliothèques et libération des ressources.

Gestion des bibliothèques

Le Core ARCADE gère les bibliothèques avec les méthodes suivantes:

detectGraphicLibraries()

Recherche les bibliothèques graphiques dans le répertoire ./lib/ avec le préfixe spécifié.

detectGameLibraries()

Recherche les bibliothèques de jeux dans le répertoire ./lib/ avec le préfixe spécifié.

loadGraphicLibrary(path)

Charge une bibliothèque graphique spécifique et instancie le module d'affichage correspondant.

bool ArcadeCore::loadGraphicLibrary(const std::string &path) {
    if (_displayModule != nullptr) {
        _displayModule->close();
        _displayLoader.unload();
    }
    
    if (!_displayLoader.load(path)) {
        return false;
    }
    
    _displayModule = _displayLoader.getInstance();
    if (_displayModule == nullptr || !_displayModule->init()) {
        _displayLoader.unload();
        return false;
    }
    
    return true;
}

loadGameLibrary(path)

Charge une bibliothèque de jeu spécifique et instancie le module de jeu correspondant.

switchNextGraphiclib() / switchPreviousGraphiclib()

Méthodes pour basculer entre les bibliothèques graphiques disponibles.