Création d'une bibliothèque de liens dynamiques pour un plugin de jeu et exécution de classes dans le programme principal

Pour développer un plugin de jeu utilisant une bibliothèque de liens dynamiques (DLL) en C++ avec l'environnement Dev-C++ 5.11, il est essentiel de configurer correctement les en-têtes et les sources, et de s'assurer que les classes définies dans la DLL sont accessibles dans le programme principal via des pointeurs de fonction et des conversions de type explicites.

Code de l'en-tête de la DLL (plugin_dll.h)

#ifndef PLUGIN_DLL_H
#define PLUGIN_DLL_H
#include <iostream>
using namespace std;

class ZoneAffichage {
public:
    ZoneAffichage(int hauteur, int largeur) {
        this->largeur = largeur;
        this->hauteur = hauteur;
        this->grille = new char*[this->hauteur];
        for (int i = 0; i < hauteur; i++) {
            this->grille[i] = new char[this->largeur];
            for (int j = 0; j < largeur; j++) {
                this->grille[i][j] = '\0';
            }
        }
    }
    char** grille;
    int largeur;
    int hauteur;
};

class Joueur {
public:
    Joueur(int x, int y, int limiteX, int limiteY) {
        posX = x;
        posY = y;
        enAttaque = 0;
        bonusActif = 0;
        deltaX = 0;
        deltaY = 0;
        this->limiteX = limiteX;
        this->limiteY = limiteY;
    }
    ~Joueur();
    char symbole = '1';
    int posX;
    int posY;
    int deltaX;
    int deltaY;
    int limiteX;
    int limiteY;
    int enAttaque;
    int bonusActif;
};

class AttaqueLineaire {
public:
    AttaqueLineaire(int porteeH, int porteeL, int duree, int id) {
        this->porteeH = porteeH;
        this->porteeL = porteeL;
        this->id = id;
        this->duree = duree;
        compteurActuel = 0;
    }
    int porteeH;
    int porteeL;
    int id;
    int duree;
    int compteurActuel;
    void executerAttaque(ZoneAffichage* zone, Joueur* joueur) {
        if (compteurActuel != duree) {
            compteurActuel++;
            for (int k = 0; k < 10; k++) {
                zone->grille[joueur->posY][joueur->posX + 1 + k] = 'P';
            }
        } else {
            compteurActuel = 0;
            joueur->enAttaque = 0;
        }
    }
};

static AttaqueLineaire* instanceAttaque = new AttaqueLineaire(20, 50, 20, 3);

extern "C" {
    void fonctionPrincipaleDLL(ZoneAffichage* zone, Joueur* joueur);
}
#endif

Code source de la DLL (plugin_dll.cpp)

#include "plugin_dll.h"
#include <windows.h>

void fonctionPrincipaleDLL(ZoneAffichage* zone, Joueur* joueur) {
    instanceAttaque->executerAttaque(zone, joueur);
}

Programme principal (jeu_principal.cpp)

#include <iostream>
#include <cstring>
#include <windows.h>

#define TOUCHE_APPUYEE(vKey) ((GetAsyncKeyState(vKey) & 0x8000) ? 1 : 0)
#define TOUCHE_FENETRE_ACTIVE(hWnd, vk) (TOUCHE_APPUYEE(vk) && GetForegroundWindow() == hWnd)

using namespace std;

class CarteJeu {
public:
    CarteJeu(int hauteur, int largeur) {
        this->largeur = largeur;
        this->hauteur = hauteur;
        donnees = new int*[this->hauteur];
        for (int i = 0; i < hauteur; i++) {
            donnees[i] = new int[this->largeur];
            for (int j = 0; j < largeur; j++) {
                donnees[i][j] = 0;
            }
        }
    }
    ~CarteJeu();
    int** donnees;
    int largeur;
    int hauteur;
};

class ZonePrincipale {
public:
    ZonePrincipale(int hauteur, int largeur) {
        this->largeur = largeur;
        this->hauteur = hauteur;
        matrice = new char*[this->hauteur];
        for (int i = 0; i < hauteur; i++) {
            matrice[i] = new char[this->largeur];
            for (int j = 0; j < largeur; j++) {
                matrice[i][j] = '\0';
            }
        }
    }
    char** matrice;
    int largeur;
    int hauteur;
    void initialiser() {
        for (int i = 0; i < this->hauteur; i++) {
            for (int j = 0; j < this->largeur - 1; j++) {
                this->matrice[i][j] = '*';
            }
            this->matrice[i][this->largeur - 1] = '\0';
        }
    }
    void rafraichir(CarteJeu* carte) {
        for (int i = 0; i < carte->hauteur; i++) {
            for (int j = 0; j < carte->largeur; j++) {
                if (carte->donnees[i][j] == 0) {
                    this->matrice[i][j] = ' ';
                }
            }
        }
    }
};

class TamponAffichage {
public:
    TamponAffichage(int hauteur, int largeur) {
        contenu = new char[largeur * hauteur + 1000];
        strcpy(contenu, "");
    }
    char* contenu;
    void remplir(ZonePrincipale* zone) {
        if (contenu == NULL) return;
        strcpy(contenu, "");
        for (int i = 0; i < zone->hauteur; i++) {
            strcat(contenu, zone->matrice[i]);
            strcat(contenu, "\n");
        }
    }
    void afficher() {
        cout << contenu;
    }
};

class Heros {
public:
    Heros(int x, int y, int maxX, int maxY) {
        coordX = x;
        coordY = y;
        attaqueEnCours = 0;
        boostActif = 0;
        depX = 0;
        depY = 0;
        this->maxX = maxX;
        this->maxY = maxY;
    }
    ~Heros();
    char avatar = '1';
    int coordX;
    int coordY;
    int depX;
    int depY;
    int maxX;
    int maxY;
    int attaqueEnCours;
    int boostActif;
    void verifierDeplacement(HWND hwnd) {
        depX = 0;
        depY = 0;
        if (TOUCHE_FENETRE_ACTIVE(hwnd, 0x41)) depX -= 1;
        if (TOUCHE_FENETRE_ACTIVE(hwnd, 0x57)) depY -= 1;
        if (TOUCHE_FENETRE_ACTIVE(hwnd, 0x44)) depX += 1;
        if (TOUCHE_FENETRE_ACTIVE(hwnd, 0x53)) depY += 1;
    }
    void limiterVitesse() {
        if (depX > 1) depX = 1;
        else if (depX < -1) depX = -1;
        if (depY > 1) depY = 1;
        else if (depY < -1) depY = -1;
    }
    void deplacer() {
        if (depX) coordX += depX;
        if (depY) coordY += depY;
    }
    void verifierLimites() {
        if (coordX >= maxX) coordX = maxX - 1;
        else if (coordX < 0) coordX = 0;
        if (coordY >= maxY) coordY = maxY - 1;
        else if (coordY < 0) coordY = 0;
    }
    void insererDansZone(ZonePrincipale* zone) {
        zone->matrice[coordY][coordX] = avatar;
    }
    void verifierAttaque(HWND hwnd) {
        if (attaqueEnCours == 0 && TOUCHE_FENETRE_ACTIVE(hwnd, 0x4A)) {
            attaqueEnCours = 1;
        }
    }
    void verifierBoost(HWND hwnd) {
        if (boostActif == 0 && TOUCHE_FENETRE_ACTIVE(hwnd, 0x4B)) {
            boostActif = 1;
        }
    }
    void editerCarte(HWND hwnd, CarteJeu* carte) {
        if (TOUCHE_FENETRE_ACTIVE(hwnd, 0x30)) carte->donnees[coordY][coordX] = 0;
        if (TOUCHE_FENETRE_ACTIVE(hwnd, 0x36)) carte->donnees[coordY][coordX] = 6;
        if (TOUCHE_FENETRE_ACTIVE(hwnd, 0x37)) carte->donnees[coordY][coordX] = 7;
        if (TOUCHE_FENETRE_ACTIVE(hwnd, 0x38)) carte->donnees[coordY][coordX] = 8;
        if (TOUCHE_FENETRE_ACTIVE(hwnd, 0x39)) carte->donnees[coordY][coordX] = 9;
    }
};

class ChargeurPlugin {
    typedef void(*FonctionPlugin)(ZonePrincipale*, Heros*);
public:
    ChargeurPlugin(char* nomDll, int identifiant) {
        HINSTANCE librairie = LoadLibrary(nomDll);
        if (librairie == NULL) {
            fonctionAtt = NULL;
        } else {
            FonctionPlugin temp = (FonctionPlugin)GetProcAddress(librairie, "fonctionPrincipaleDLL");
            if (temp == NULL) {
                fonctionAtt = NULL;
            } else {
                fonctionAtt = temp;
            }
        }
        compteurEchec = 0;
    }
    FonctionPlugin fonctionAtt;
    int compteurEchec;
    void appliquerAttaque(ZonePrincipale* zone, Heros* heros) {
        if (heros->attaqueEnCours && fonctionAtt != NULL) {
            fonctionAtt(zone, heros);
        } else if (heros->attaqueEnCours && fonctionAtt == NULL) {
            compteurEchec++;
            if (compteurEchec > 10) {
                heros->attaqueEnCours = 0;
                compteurEchec = 0;
            }
        }
    }
};

int main() {
    CarteJeu* carteJeu = new CarteJeu(20, 50);
    ZonePrincipale* zone = new ZonePrincipale(20, 50);
    TamponAffichage* tampon = new TamponAffichage(20, 80);
    ChargeurPlugin* chargeur = new ChargeurPlugin("plugin.dll", 3);
    zone->rafraichir(carteJeu);
    tampon->remplir(zone);
    tampon->afficher();

    HWND hwnd = GetForegroundWindow();
    Heros* heros = new Heros(0, 0, 50, 20);

    while (1) {
        if (TOUCHE_FENETRE_ACTIVE(hwnd, VK_ESCAPE)) break;
        if (TOUCHE_FENETRE_ACTIVE(hwnd, 0x31)) heros->attaqueEnCours = 1;

        heros->verifierDeplacement(hwnd);
        heros->limiterVitesse();
        heros->deplacer();
        heros->verifierLimites();
        zone->rafraichir(carteJeu);

        chargeur->appliquerAttaque(zone, heros);
        heros->insererDansZone(zone);

        tampon->remplir(zone);
        tampon->afficher();
        Sleep(100);
        system("cls");
    }
    return 0;
}

Pour que le plugin fonctionne correctement, assurez-vous que les noms de classes dans la DLL correspondent à ceux du programme principal. Après la fermeture du jeu, attendez 30 à 50 secondes pour que la DLL se décharge proprement avant de relancer l'application, sinon les éléments graphiques risquent de ne pas s'afficher.

Étiquettes: dll C++ Dev-C++ game plugin function pointers

Publié le 29 juin à 06h05