Skip to content

DuckDuckGame

DuckDuckGame est un clone de Flappy Bird et surtout le prétexte pour construire un moteur de jeu 2D en C++ avec SDL2.

Projet de cours de C, réalisé sur deux mois. L’objectif était de construire un jeu fonctionnel, mais après une première version en C, j’ai fini par demander l’accord du prof pour tout réécrire en C++, les limites du C pour de l’orienté objet étaient trop frustrantes pour ignorer. C’était aussi mon premier projet en C++, j’ai tout appris en avançant.

La première version était en C pur. J’essayais de reproduire de l’orienté objet sans en avoir les outils : des structs avec des pointeurs de fonctions, des conventions de nommage pour simuler des méthodes, bref, réinventer la roue de manière bancale. Ça fonctionnait, mais le code était difficile à faire évoluer. Un des problèmes récurrents était de trouver le bon niveau d’abstraction : ni trop rigide, ni over-engineeré. J’ai fini par tout jeter.

Repartir de zéro avec C++. Les classes réglaient exactement les problèmes que j’avais en C, et j’en ai profité pour concevoir une architecture inspirée de Unity, que je connaissais bien à travers des projets antérieurs : un Entity Component System.

Schéma architecture

Le moteur repose sur une séparation stricte entre le code moteur (Engine/) et le code jeu (Game/). Le jeu ne fait qu’utiliser les abstractions du moteur.

Chaque objet du jeu est une Entity. Une entité en elle-même ne fait rien : c’est une collection de composants qui définissent son comportement.

// Ajouter un composant à une entité
player->addComponent<PhysicsComponent>();
player->addComponent<ImageVisualComponent>("Duck.png");
// Y accéder depuis n'importe où
auto* physics = player->getComponent<PhysicsComponent>();

Les composants disponibles :

  • TransformComponent : position et taille
  • PhysicsComponent : vélocité, collider, rebond, calcul de la prochaine position
  • ImageVisualComponent, TextVisualComponent, ButtonVisualComponent : rendu

Le jeu est organisé en scènes (menu principal, partie normale, partie difficile) gérées par un SceneManager. Chaque scène instancie ses entités et gère son cycle de vie.

  • Camera : gestion du viewport
  • Inputs : abstraction des événements SDL
  • Time : delta time pour une physique indépendante du framerate
  • ScoreManager : persistance des scores sur disque

La version C avait une identité propre, assez différente de Flappy Bird classique.
Les tuyaux ne faisaient pas perdre : ils faisaient rebondir. On pouvait donc se prendre un tuyau, être projeté vers la gauche, et recover. Sortir de l’écran par la gauche faisait perdre.
Chaque saut donnait un léger boost de vitesse vers l’avant, et maintenir Shift augmentait la gravité. Un fond avec des nuages défilant moins vite que le sol donnait un effet de parallaxe.
Le jeu avait une fin : un drapeau de victoire au bout du niveau, avec une barre de progression en haut de l’écran indiquant la distance restante.

Ce que cette version n’avait pas : score, menu, delta time (vitesse donc fixée à 60fps, sans ralenti à la mort).

La version C++ abandonne le côté “course vers un drapeau” pour un score à l’infini plus proche de Flappy Bird.
Toucher un tuyau fait perdre. Un menu propose deux modes : normal et hardcore, où la vitesse augmente progressivement au fil de la partie. Le score est sauvegardé dans un fichier entre les parties, et des transitions animées accompagnent les changements de scène.

Deux features de la version C n’ont pas été réimplémentées : la rotation visuelle du joueur en fonction de sa vélocité (detail visuel sympa), et l’effet de parallaxe, qui aurait demandé une architecture caméra plus complexe avec la deadline qui approchait.

Menu principalGameplayVersion C (legacy)

J’ai documenté en détail la construction du système de physique dans cet article :

Et voici l’accès au repo Github :