Skip to content

Troisième exemple : dessin de plusieurs objets et mouvements de caméra

Pour les exemples qui suivent, nous nous concentrerons que sur la partie raylib, et nous ne modifierons pas les fichiers main_raylib.cpp, dessinable.h et support_a_dessin.h. Vous pouvez donc simplement copier ces fichiers dans le nouveau sous-répertoire pour votre troisième exemple ; voire même copier toute la structure, p.ex. sous Unix :

mkdir TroisiemeExemple
cp -r DeuxiemeExemple/CMakeLists.txt DeuxiemeExemple/general DeuxiemeExemple/raylib TroisiemeExemple
Il suffira alors simplement d'éditer les fichiers à modifier.

Par ailleurs, on pourrait aussi, bien sûr, adapter la partie « texte » de façon similaire aux adaptations que nous allons ici apporter à la partie raylib. Mais ce n'est pas l'objet du présent tutoriel.

Plusieurs vrais objets

Afin d'avoir un peu d'intérêt à l'exemple, nous allons créer des contenus un peu plus pertients. Modifions general/contenu.h comme suit :

// ... (en-têtes)

enum Couleur {
    NONE,
    ROUGE,
    VERT,
    BLEU
};

struct Position {
    double x;
    double y;
    double z;
};

class Contenu : public Dessinable {
public:
    // ... (comme avant)
    // mais SUPPRIMER le cteur par défaut:   Contenu() = default;
    // Le remplacer par :

    Contenu(const Position &p = {0, 0, 0}, const Couleur c = NONE)
    : position(p), color(c) {}

    // ... (comme avant)

    Position get_position() const { return position; }
    Couleur get_color() const { return color; }

private:
    Position position;
    Couleur  color;
};

Ceci ajoute donc une position et une couleur aux contenus. Nous pouvons aussi modifier la déclaration de raylibRender (dans raylib/raylib_render.h) afin d'avoir plusieurs contenus à afficher :

// ... (en-têtes)
#include <vector>

class raylibRender : public SupportADessin {
    // ... (comme avant)

private:
    // ... (Camera3D comme avant)
    // Remplacer : Contenu c;
    // Par :
    std::vector<Contenu> liste_contenus;
};

et son initialisation par défaut dans raylib/raylib_render.cpp :

// ... (en-têtes)

raylibRender::raylibRender()
: liste_contenus({
      Contenu(),
      Contenu({-1,1,1}, VERT),
      Contenu({-1,0,1}, ROUGE)
  })
{
    // ... (comme avant)
}

Bien sûr, il faut modifier La méthode dessine() pour utiliser les propriétés de Contenu :

void raylibRender::dessine(Contenu const& a_dessiner)
{
    const auto [x, y, z] = a_dessiner.get_position();
    const Vector3 position = { static_cast<float>(x), static_cast<float>(y), static_cast<float>(z) };
    auto color = WHITE;
    switch (a_dessiner.get_color()) {
        case ROUGE:
            color = RED;
            break;
        case VERT:
            color = GREEN;
            break;
        case BLEU:
            color = BLUE;
            break;
        default:
            color = WHITE;
            break;
    }
    DrawCube(position, 1.0f, 1.0f, 1.0f, color);
    DrawCubeWires(position, 1.0f, 1.0f, 1.0f, BLACK);
}

Note : les Contenu::position étant en double, mais les posistions dans la raylib en float, on doit forcer la conversion via les static_cast<float>(...). (On aurait évidemment pu mettre des float dès le départ, mais, restant fidèle à l'indépendance entre coeur de la simulation (Contenu) et représentation (raylib), un choix local de la bibliothèque de visualisation ne doit pas affecter la conception générale du coeur du modèle !)

Finalement, on doit aussi adapter la méthode run() pour faire une boucle sur la liste des contenus :

void raylibRender::run() {
   // ...
   // Remplacer :   c.dessine_sur(*this);
   // par :
   for (auto const& contenu : liste_contenus) {
       contenu.dessine_sur(*this);
   }
}

On peut essayer compiler et voir l'effet de nos modifications :

  • ajoutez le nouveau dossier au CMakeLists.txt principal : add_subdirectory(TroisiemeExemple) ;
  • supprimez la ligne add_subdirectory(text) de TroisiemeExemple/CMakeLists.txt ;
  • remplacez trois fois Dessin par Dessin3 dans chacune des lignes de TroisiemeExemple/general/CMakeLists.txt ;
  • remplacez DeuxiemeExemple par TroisiemeExemple dans la dernière ligne de TroisiemeExemple/general/CMakeLists.txt ;
  • dans TroisiemeExemple/raylib/CMakeLists.txt :
    • remplacez quatre fois RayRender par RayRender3 ;
    • remplacez une fois Dessin par Dessin3 ;
    • remplacez trois fois exemple2_raylib par exemple3 :
add_library(RayRender3 raylib_render.h raylib_render.cpp)
target_compile_options(RayRender3 PRIVATE ${PROJECT_WARNING_FLAGS})
target_link_libraries(RayRender3 raylib Dessin3)

add_executable(exemple3 main_raylib.cpp)
target_compile_options(exemple3 PRIVATE ${PROJECT_WARNING_FLAGS})
target_link_libraries(exemple3 RayRender3)

Vous pouvez ensuite aller dans build et faire

cmake ..
cmake --build .

puis lancer bin/exemple3. Vous devriez y voir trois cube (rouge, vert et blanc) au lieu d'un seul (illustré ici sans la grille) :

ex3_img.png

Mouvements de caméra

Si l'on veut permettre le movement de la caméra, il suffit d'ajouter la fonction UpdateCamera() de raylib :

void raylibRender::run() {
    while (!WindowShouldClose()) {
        UpdateCamera(&camera, CAMERA_FREE);
        // ... (suite comme avant)
}

UpdateCamera() prend en paramètre la caméra à mettre à jour et le type de mouvement, ici CAMERA_FREE, qui gére le mouvement via la souris et les touches W, A, S et D (d'autres modes de mouvement sont présentés ici).

Recompilez et essayez les déplacements. Attention la caméra est sensible à la souris et il se peut donc qu'en ayant amené la souris sur la fenêtre vous ayez déplacé le point de vue ; bougez alors la souris pour voir les cubes.