mardi 10 juin 2025

Créons Flappy Bird


 

Créons Flappy Bird : Un Projet Idéal pour Débuter en Programmation de Jeux

Qui n'a jamais entendu parler de Flappy Bird ? Ce jeu mobile, en apparence simpliste, a captivé (et parfois frustré !) des millions de joueurs à travers le monde. Son concept est enfantin : faites voler un oiseau entre des tuyaux sans le faire tomber ni le faire s'écraser. Mais derrière cette simplicité se cachent des mécaniques de jeu fondamentales, parfaites pour apprendre les bases de la programmation de jeux vidéo.

L'histoire d'un phénomène inattendu

Flappy Bird a été créé en 2013 par un développeur vietnamien, Dong Nguyen, en seulement quelques jours. Le jeu a explosé en popularité début 2014, devenant un succès mondial inattendu. Son secret ? Une difficulté exigeante, un concept addictif et un style graphique rétro inspiré des jeux 8-bit. Malgré son succès fulgurant, Dong Nguyen l'a retiré des magasins d'applications, citant l'addiction qu'il générait. Cela n'a fait qu'alimenter sa légende, et le jeu est depuis devenu un classique pour les développeurs indépendants qui cherchent à recréer ses mécaniques pour l'apprentissage.

Pourquoi Flappy Bird est parfait pour apprendre à coder un jeu ?

Pour les débutants en programmation de jeux, Flappy Bird est un trésor. Il permet d'explorer des concepts clés sans se noyer dans la complexité :

  • Gestion des entrées utilisateur : Comment réagir aux pressions de touche.

  • Physique simplifiée : La gravité et les sauts (impulsions).

  • Détection de collisions : Savoir quand l'oiseau touche les tuyaux ou le sol.

  • Génération d'objets dynamiques : Faire apparaître de nouveaux tuyaux à l'infini.

  • Gestion des états de jeu : Écran de démarrage, jeu en cours, fin de partie.

  • Animation simple : Animer un sprite avec quelques images.

  • Système de score : Suivre la progression du joueur.

Nous allons recréer une version complète de Flappy Bird en utilisant Love2D, un framework de jeu fantastique pour Lua.

Le Code de Flappy Bird (pas à pas)

Voici le code complet du jeu. Nous allons le parcourir section par section pour comprendre comment chaque partie fonctionne.

1. Variables Globales et Paramètres du Jeu

Au début du fichier, nous définissons toutes les variables importantes qui contrôlent le comportement du jeu, la taille de la fenêtre, la vitesse de l'oiseau, la fréquence des tuyaux, etc. Ces valeurs peuvent être ajustées pour modifier la difficulté ou l'apparence du jeu.

-- main.lua - Un clone simple de Flappy Bird pour Love2D
-- Ce code est conçu pour expliquer les bases de la programmation de jeux aux débutants.

-- [[ Variables Globales du Jeu ]]
-- Ces variables définissent les paramètres de base de notre jeu.
WINDOW_WIDTH = 800
WINDOW_HEIGHT = 600

-- Définitions du joueur (maintenant appelé "oiseau" pour la généralité)
BIRD_RADIUS = 20                 -- Rayon de collision logique de l'oiseau.
BIRD_X = WINDOW_WIDTH / 4        -- Position X fixe de l'oiseau sur l'écran.
BIRD_Y = WINDOW_HEIGHT / 2       -- Position Y initiale de l'oiseau.
BIRD_GRAVITY = 1000              -- Force de gravité qui tire l'oiseau vers le bas (pixels/s^2).
BIRD_FLAP_VELOCITY = -400        -- Vitesse verticale du saut lorsque l'oiseau "bat des ailes" (pixels/s).
bird_velocity_y = 0              -- Vitesse verticale actuelle de l'oiseau.
bird_y = BIRD_Y                  -- Position Y actuelle de l'oiseau.

-- Définitions des tuyaux (obstacles)
PIPE_WIDTH = 80                  -- Largeur des tuyaux.
PIPE_GAP_HEIGHT = 180            -- Hauteur de l'espace par lequel l'oiseau doit passer.
PIPE_SPEED = 200                 -- Vitesse de défilement des tuyaux (pixels/s).
PIPE_SPAWN_INTERVAL = 2          -- Temps entre l'apparition de deux tuyaux (en secondes).
pipe_spawn_timer = 0             -- Compteur pour gérer l'apparition des tuyaux.
pipes = {}                       -- Table pour stocker tous les tuyaux actifs à l'écran.

-- Score du joueur
score = 0

-- États du jeu
-- Le jeu peut être dans différents états: "start" (écran de démarrage), "playing" (en jeu), "gameover" (fin de partie).
GAME_STATE = "start"

-- Couleurs utilisées dans le jeu (le fond et l'oiseau utiliseront des images, mais ces couleurs restent pour le sol et le texte).
COLOR_BIRD = {1, 1, 0.2}         -- Couleur de l'oiseau (si dessinée sans image).
COLOR_PIPE_TOP = {0.2, 0.7, 0.2} -- Couleur du haut des tuyaux (si dessinée sans image).
COLOR_PIPE_BOTTOM = {0.2, 0.6, 0.2} -- Couleur du bas des tuyaux (si dessinée sans image).
COLOR_BACKGROUND = {0.4, 0.6, 1} -- Couleur de fond par défaut (sera recouverte par l'image).
COLOR_TEXT = {1, 1, 1}           -- Couleur blanche pour le texte.
COLOR_GROUND = {0.3, 0.2, 0.1}   -- Couleur marron pour le sol.

-- Hauteur du sol, pour la détection de collision.
GROUND_HEIGHT = 50

-- Variables pour les images chargées (elles seront initialisées dans love.load()).
background_image = nil
bird_sprite_0 = nil              -- Première image du sprite de l'oiseau.
bird_sprite_1 = nil              -- Deuxième image du sprite de l'oiseau (pour l'animation).
pipe_top_image = nil    -- Image pour le tuyau du haut (était pipe2.png).
pipe_bottom_image = nil -- Image pour le tuyau du bas (était pipe.png).

-- Variables d'animation de l'oiseau
current_player_frame = 1         -- Frame d'animation actuelle (1 ou 2).
animation_timer = 0              -- Compteur pour le temps écoulé avant de changer de frame.
animation_speed = 0.08           -- Vitesse de l'animation (changer de frame toutes les 0.08 secondes).

-- Nombre de frames disponibles pour l'animation de l'oiseau.
PLAYER_FRAME_COUNT = 2

-- Couleurs arc-en-ciel pour le texte de l'écran de démarrage.
local rainbow_colors = {
    {1, 0, 0},     -- Rouge
    {1, 0.5, 0},   -- Orange
    {1, 1, 0},     -- Jaune
    {0, 1, 0},     -- Vert
    {0, 0.5, 1},   -- Bleu clair
    {0, 0, 1},     -- Bleu foncé
    {0.5, 0, 1}    -- Violet
}

-- Fonction utilitaire : getTableLength(t)
-- Cette fonction calcule la taille d'une table (nombre d'éléments).
-- Elle est utilisée pour la compatibilité avec certains environnements Lua.
local function getTableLength(t)
    local count = 0
    for _ in pairs(t) do
        count = count + 1
    end
    return count
end

-- Fonction pour dessiner du texte avec des couleurs arc-en-ciel.
-- text_str: la chaîne de caractères à dessiner.
-- x, y: la position de départ du texte.
-- font: la police à utiliser.
-- color_offset: un décalage optionnel pour varier le début de l'arc-en-ciel.
local function drawTextRainbow(text_str, x, y, font, color_offset)
    color_offset = color_offset or 0
    local current_x = x
    love.graphics.setFont(font) -- S'assurer que la bonne police est utilisée.
    for i = 1, #text_str do
        local char = text_str:sub(i, i)
        local char_width = font:getWidth(char)
        -- Calcul de l'index de couleur pour chaque caractère, créant l'effet arc-en-ciel.
        local color_index = (i - 1 + color_offset) % getTableLength(rainbow_colors) + 1
        love.graphics.setColor(rainbow_colors[color_index])
        love.graphics.print(char, current_x, y)
        current_x = current_x + char_width
    end
end

2. La Fonction love.load() : Les Préparatifs

La fonction love.load() est le point de départ de votre jeu. Love2D l'appelle une seule fois, au tout début. C'est ici que vous définissez la taille de la fenêtre, chargez toutes vos images (les sprites de l'oiseau, les tuyaux et le fond) et initialisez les variables du jeu pour la première partie.

-- [[ love.load() ]]
-- Cette fonction est appelée une seule fois au début du jeu.
-- Elle est utilisée pour charger les ressources (images, sons) et initialiser les variables de départ.
function love.load()
    love.window.setTitle("Flappy Bird Love2D") -- Définit le titre de la fenêtre.
    love.window.setMode(WINDOW_WIDTH, WINDOW_HEIGHT) -- Définit la taille de la fenêtre.
    
    -- Charger les images depuis le dossier "images".
    background_image = love.graphics.newImage("images/flappy bird wallpaper.jpeg")
    bird_sprite_0 = love.graphics.newImage("images/sprite_0.png")
    bird_sprite_1 = love.graphics.newImage("images/sprite_1.png")
    
    -- Charger les images des tuyaux (attention à l'inversion demandée).
    pipe_top_image = love.graphics.newImage("images/pipe2.png")    -- Ceci est l'image pour le tuyau du haut.
    pipe_bottom_image = love.graphics.newImage("images/pipe.png") -- Ceci est l'image pour le tuyau du bas.

    love.graphics.setFont(love.graphics.newFont(30)) -- Définit la police par défaut pour le texte.
    math.randomseed(os.time()) -- Initialise le  générateur de nombres aléatoires (pour des tuyaux différents à chaque partie).
    
    -- Réinitialise toutes les variables pour commencer une nouvelle partie.
    resetGame()
end

-- Fonction : resetGame()
-- Réinitialise l'état du jeu pour une nouvelle partie.
function resetGame()
    bird_y = BIRD_Y             -- Position Y de l'oiseau remise à l'initiale.
    bird_velocity_y = 0         -- Vitesse de l'oiseau remise à zéro.
    pipes = {}                  -- Vide la table des tuyaux.
    score = 0                   -- Score remis à zéro.
    pipe_spawn_timer = PIPE_SPAWN_INTERVAL -- Le timer est réinitialisé pour faire apparaître le premier tuyau.
    GAME_STATE = "start"        -- Le jeu revient à l'écran de démarrage.
    current_player_frame = 1    -- L'animation de l'oiseau est réinitialisée.
    animation_timer = 0
end

3. La Fonction love.update(dt) : Le Cœur de la Logique

love.update(dt) est la fonction la plus importante de votre jeu. Love2D l'appelle à chaque frame (des dizaines de fois par seconde !). C'est là que toute la logique du jeu se déroule :

  • Mouvement de l'oiseau : La gravité est appliquée pour le faire tomber, et la vitesse verticale est mise à jour.

  • Animation : Le sprite de l'oiseau change de frame pour créer l'illusion de mouvement.

  • Génération des tuyaux : Un compte à rebours gère l'apparition de nouveaux tuyaux à l'écran.

  • Déplacement des tuyaux : Tous les tuyaux existants se déplacent vers la gauche.

  • Détection de collisions : On vérifie si l'oiseau touche un tuyau ou le sol.

  • Gestion du score : Le score augmente lorsque l'oiseau passe un tuyau.

  • Changement d'état du jeu : Passage de l'état "playing" à "gameover" en cas de collision.

-- [[ love.update(dt) ]]
-- Cette fonction est appelée à chaque frame du jeu.
-- Elle est utilisée pour mettre à jour la logique du jeu : mouvements, collisions, génération d'obstacles, etc.
-- 'dt' (delta time) est le temps écoulé depuis la dernière frame, utile pour des mouvements fluides quelle que soit la performance de l'ordinateur.
function love.update(dt)
    -- Met à jour le timer d'animation de l'oiseau.
    animation_timer = animation_timer + dt
    if animation_timer >= animation_speed then
        -- Change la frame de l'oiseau pour créer l'animation (passe de 1 à 2, puis de 2 à 1).
        current_player_frame = current_player_frame % PLAYER_FRAME_COUNT + 1
        animation_timer = animation_timer - animation_speed
    end

    -- La logique du jeu ne s'exécute que si l'état est "playing" ou "gameover".
    if GAME_STATE == "playing" then
        -- Applique la gravité à l'oiseau.
        bird_velocity_y = bird_velocity_y + BIRD_GRAVITY * dt
        bird_y = bird_y + bird_velocity_y * dt

        -- Empêche l'oiseau de sortir par le haut de l'écran.
        if bird_y < 0 then
            bird_y = 0
            bird_velocity_y = 0
        end

        -- Vérifie la collision avec le sol.
        if bird_y + BIRD_RADIUS >= WINDOW_HEIGHT - GROUND_HEIGHT then
            bird_y = WINDOW_HEIGHT - GROUND_HEIGHT - BIRD_RADIUS
            GAME_STATE = "gameover" -- Si l'oiseau touche le sol, c'est "gameover".
            bird_velocity_y = 0
        end

        -- Gère le timer d'apparition des tuyaux.
        pipe_spawn_timer = pipe_spawn_timer - dt
        if pipe_spawn_timer <= 0 then
            -- Génère une nouvelle paire de tuyaux (un en haut, un en bas) avec un espace aléatoire.
            local gap_y = math.random(PIPE_GAP_HEIGHT, WINDOW_HEIGHT - GROUND_HEIGHT - PIPE_GAP_HEIGHT)
            table.insert(pipes, {
                x = WINDOW_WIDTH,      -- Le tuyau apparaît à droite de l'écran.
                gap_y = gap_y,         -- Position verticale de l'espace.
                passed = false         -- Indique si l'oiseau a déjà passé ce tuyau (pour le score).
            })
            pipe_spawn_timer = PIPE_SPAWN_INTERVAL -- Réinitialise le timer pour le prochain tuyau.
        end

        -- Parcourt tous les tuyaux existants.
        for i = getTableLength(pipes), 1, -1 do -- On parcourt à l'envers pour pouvoir supprimer des tuyaux en toute sécurité.
            local pipe = pipes[i]
            pipe.x = pipe.x - PIPE_SPEED * dt -- Déplace le tuyau vers la gauche.

            -- Détection de collision (AABB - Bounding Box Alignée sur les Axes)
            -- Vérifie si l'oiseau entre en collision avec le tuyau du haut ou du bas.
            local bird_collides_with_top_pipe = 
                BIRD_X + BIRD_RADIUS > pipe.x and BIRD_X - BIRD_RADIUS < pipe.x + PIPE_WIDTH and
                bird_y - BIRD_RADIUS < pipe.gap_y - PIPE_GAP_HEIGHT / 2

            local bird_collides_with_bottom_pipe =
                BIRD_X + BIRD_RADIUS > pipe.x and BIRD_X - BIRD_RADIUS < pipe.x + PIPE_WIDTH and
                bird_y + BIRD_RADIUS > pipe.gap_y + PIPE_GAP_HEIGHT / 2

            if bird_collides_with_top_pipe or bird_collides_with_bottom_pipe then
                GAME_STATE = "gameover" -- Collision détectée, c'est "gameover".
            end

            -- Augmente le score si l'oiseau a passé le tuyau sans collision.
            if pipe.x + PIPE_WIDTH < BIRD_X and not pipe.passed then
                score = score + 1
                pipe.passed = true -- Marque le tuyau comme passé.
            end

            -- Supprime les tuyaux qui sont sortis de l'écran à gauche.
            if pipe.x + PIPE_WIDTH < 0 then
                table.remove(pipes, i)
            end
        end

    elseif GAME_STATE == "gameover" then
        -- Si le jeu est terminé, l'oiseau continue de tomber jusqu'à toucher le sol.
        bird_velocity_y = bird_velocity_y + BIRD_GRAVITY * dt
        bird_y = bird_y + bird_velocity_y * dt
        if bird_y + BIRD_RADIUS >= WINDOW_HEIGHT - GROUND_HEIGHT then
            bird_y = WINDOW_HEIGHT - GROUND_HEIGHT - BIRD_RADIUS
            bird_velocity_y = 0
        end
    end
end

4. La Fonction love.draw() : L'Affichage du Jeu

La fonction love.draw() est responsable de tout ce que vous voyez à l'écran. Elle est appelée juste après love.update() pour redessiner le jeu avec les dernières mises à jour.

  • Gestion des écrans : Elle vérifie l'état actuel du jeu (GAME_STATE) pour savoir s'il faut afficher l'écran de démarrage avec les instructions ou l'écran de jeu/fin de partie.

  • Dessin du fond : L'image de fond est dessinée en premier.

  • Dessin du sol : Le sol est dessiné par-dessus le fond.

  • Dessin des tuyaux : Chaque tuyau est dessiné à sa position actuelle.

  • Dessin de l'oiseau : L'image de l'oiseau est dessinée, en tenant compte de la frame d'animation actuelle et de sa position.

  • Affichage du score et des messages : Le score est affiché en haut à gauche, et des messages (comme "GAME OVER") apparaissent selon l'état du jeu.

  • Effet Arc-en-ciel : Le texte "ARCADE FORGE" utilise un color_offset basé sur le temps pour faire défiler les couleurs, créant un effet visuel amusant.

-- [[ love.draw() ]]
-- Cette fonction est appelée à chaque frame pour dessiner tous les éléments à l'écran.
function love.draw()
    -- Si le jeu est à l'état "start", on affiche l'écran de démarrage.
    if GAME_STATE == "start" then
        -- Dessine le fond noir de l'écran de démarrage.
        love.graphics.setColor(0, 0, 0) -- Noir
        love.graphics.rectangle("fill", 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT)

        -- Dessine le texte "ARCADE FORGE" avec des couleurs arc-en-ciel qui défilent.
        local title_font = love.graphics.newFont(60)
        local title_text = "ARCADE FORGE"
        local title_width = title_font:getWidth(title_text)
        local title_x = (WINDOW_WIDTH - title_width) / 2
        local title_y = WINDOW_HEIGHT / 4 - 40 
        
        -- Le décalage des couleurs change avec le temps pour créer l'effet de défilement.
        local rainbow_offset_time = math.floor(love.timer.getTime() * 10) % getTableLength(rainbow_colors)
        drawTextRainbow(title_text, title_x, title_y, title_font, rainbow_offset_time)

        -- Dessine le titre du jeu "Flappy Bird".
        love.graphics.setColor(COLOR_TEXT) -- Blanc
        local game_title_font = love.graphics.newFont(80)
        love.graphics.setFont(game_title_font)
        local game_title_text = "Flappy Bird"
        local game_title_width = game_title_font:getWidth(game_title_text)
        local game_title_x = (WINDOW_WIDTH - game_title_width) / 2
        local game_title_y = title_y + title_font:getHeight() + 20 
        love.graphics.printf(game_title_text, game_title_x, game_title_y, game_title_width, "center")

        -- Affiche les instructions du jeu.
        love.graphics.setColor(COLOR_TEXT) -- Blanc
        local instructions_font = love.graphics.newFont(25)
        love.graphics.setFont(instructions_font)
        local instructions = {
            "Évitez les tuyaux et le sol avec votre oiseau !",
            "", -- Ligne vide pour l'espacement.
            "Appuyez sur ESPACE pour le faire voler.",
            "Appuyez sur 'R' pour rejouer après un GAME OVER."
        }
        local instructions_y = WINDOW_HEIGHT / 2 + 50 

        local current_y = instructions_y
        for _, line in ipairs(instructions) do
            love.graphics.printf(line, 0, current_y, WINDOW_WIDTH, "center")
            current_y = current_y + instructions_font:getHeight() + 5
        end

    else -- Si le jeu est en mode "playing" ou "gameover", on dessine les éléments du jeu.
        -- Dessine l'image de fond du jeu.
        love.graphics.setColor(1, 1, 1) -- Utilise la couleur blanche par défaut pour les images.
        local bg_scale_x = WINDOW_WIDTH / background_image:getWidth()
        local bg_scale_y = WINDOW_HEIGHT / background_image:getHeight()
        love.graphics.draw(background_image, 0, 0, 0, bg_scale_x, bg_scale_y)

        -- Dessine le sol (par-dessus le fond).
        love.graphics.setColor(COLOR_GROUND)
        love.graphics.rectangle("fill", 0, WINDOW_HEIGHT - GROUND_HEIGHT, WINDOW_WIDTH, GROUND_HEIGHT)

        -- Dessine les tuyaux.
        love.graphics.setColor(1, 1, 1) -- Réinitialise la couleur pour les images de tuyaux.
        for _, pipe in ipairs(pipes) do
            -- Tuyau du haut.
            local top_pipe_height = pipe.gap_y - PIPE_GAP_HEIGHT / 2
            -- Vérifie que la hauteur est positive pour éviter les erreurs de dessin.
            if top_pipe_height > 0 then
                local pipe_scale_x = PIPE_WIDTH / pipe_top_image:getWidth()
                local pipe_scale_y = top_pipe_height / pipe_top_image:getHeight()
                love.graphics.draw(pipe_top_image, pipe.x, 0, 0, pipe_scale_x, pipe_scale_y)
            end
            
            -- Tuyau du bas.
            local bottom_pipe_y = pipe.gap_y + PIPE_GAP_HEIGHT / 2
            local bottom_pipe_height = WINDOW_HEIGHT - GROUND_HEIGHT - bottom_pipe_y
            -- Vérifie que la hauteur est positive pour éviter les erreurs de dessin.
            if bottom_pipe_height > 0 then
                local pipe_scale_x = PIPE_WIDTH / pipe_bottom_image:getWidth()
                local pipe_scale_y = bottom_pipe_height / pipe_bottom_image:getHeight()
                love.graphics.draw(pipe_bottom_image, pipe.x, bottom_pipe_y, 0, pipe_scale_x, pipe_scale_y)
            end
        end

        -- Dessine l'oiseau.
        love.graphics.setColor(1, 1, 1) -- L'image contient déjà sa couleur.
        local current_bird_sprite = (current_player_frame == 1) and bird_sprite_0 or bird_sprite_1
        
        -- Calcule la taille cible de l'oiseau sur l'écran.
        local bird_target_width = BIRD_RADIUS * 2.5 
        local bird_target_height = BIRD_RADIUS * 1.5 
        
        -- Calcule les facteurs de mise à l'échelle pour l'image.
        local scale_x = bird_target_width / current_bird_sprite:getWidth()
        local scale_y = bird_target_height / current_bird_sprite:getHeight()

        -- Dessine l'image de l'oiseau, centrée à sa position logique.
        love.graphics.draw(
            current_bird_sprite,
            BIRD_X, -- Position X du centre de l'oiseau.
            bird_y, -- Position Y du centre de l'oiseau.
            0,      -- Pas de rotation pour l'instant.
            scale_x, scale_y, -- Applique la mise à l'échelle.
            current_bird_sprite:getWidth() / 2, current_bird_sprite:getHeight() / 2 -- Définit l'origine du dessin au centre de l'image.
        )

        -- Affiche le score actuel.
        love.graphics.setColor(COLOR_TEXT)
        love.graphics.print("Score: " .. score, 10, 10)

        -- Affiche le message "GAME OVER" si le jeu est terminé.
        if GAME_STATE == "gameover" then
            love.graphics.setFont(love.graphics.newFont(50))
            love.graphics.setColor(1, 0.2, 0.2) -- Rouge vif pour "GAME OVER".
            love.graphics.printf("GAME OVER", 0, WINDOW_HEIGHT / 2 - 60, WINDOW_WIDTH, "center")
            love.graphics.setColor(COLOR_TEXT)
            love.graphics.setFont(love.graphics.newFont(30))
            love.graphics.printf("Score final: " .. score, 0, WINDOW_HEIGHT / 2, WINDOW_WIDTH, "center")
            love.graphics.setFont(love.graphics.newFont(25))
            love.graphics.printf("Appuyez sur 'R' pour rejouer", 0, WINDOW_HEIGHT / 2 + 50, WINDOW_WIDTH, "center")
        end
    end
end

5. La Fonction love.keypressed(key) : Gérer les Actions du Joueur

Cette fonction est appelée chaque fois qu'une touche du clavier est enfoncée. C'est le moyen le plus simple de gérer les interactions du joueur dans Love2D.

  • Saut de l'oiseau : Lorsque la touche ESPACE est pressée, l'oiseau reçoit une impulsion vers le haut.

  • Démarrage du jeu : Si le jeu est à l'écran de démarrage et que ESPACE est pressé, le jeu passe à l'état "playing".

  • Redémarrage du jeu : Si la touche R est pressée après un "GAME OVER", la fonction resetGame() est appelée pour recommencer une partie.

-- [[ love.keypressed(key) ]]
-- Cette fonction est appelée chaque fois qu'une touche du clavier est enfoncée.
-- 'key' est le nom de la touche pressée (ex: "space", "r", "left").
function love.keypressed(key)
    -- Si la touche ESPACE est pressée.
    if key == "space" then
        -- Si le jeu est à l'état "start", on passe en mode "playing" et l'oiseau fait son premier saut.
        if GAME_STATE == "start" then
            GAME_STATE = "playing"
            bird_velocity_y = BIRD_FLAP_VELOCITY 
        -- Si le jeu est déjà en mode "playing", l'oiseau fait un saut normal.
        elseif GAME_STATE == "playing" then
            bird_velocity_y = BIRD_FLAP_VELOCITY
        end
    -- Si la touche 'R' est pressée et que le jeu est terminé.
    elseif key == "r" and GAME_STATE == "gameover" then
        resetGame() -- Réinitialise le jeu pour une nouvelle partie.
    end
end

Conclusion

Voilà ! Vous avez maintenant un jeu Flappy Bird fonctionnel, le tout écrit en Lua avec Love2D. Ce projet vous a permis de toucher à des concepts essentiels de la programmation de jeux :

  • La boucle de jeu : Comment love.update() et love.draw() travaillent ensemble.

  • La gestion des états : Comment faire évoluer le jeu à travers différentes phases.

  • La physique de base : Gravité et impulsion.

  • La détection de collision : Comment les objets interagissent.

  • L'animation de sprites : Utiliser plusieurs images pour créer un mouvement.

  • L'intégration d'assets : Charger et afficher des images.

N'hésitez pas à modifier les variables, à changer les couleurs, ou même à essayer de créer de nouveaux sprites pour personnaliser davantage votre jeu. Le monde du développement de jeux est à portée de main !

 Pour jouer au jeu cliquez ici

Pour télécharger le code source complet cliquez ici sur notre page itch

  

Aucun commentaire:

Enregistrer un commentaire

Le Phénomène Pac-Man : L'icône qui a dévoré le monde de l'arcade

À l'époque où les bornes d'arcade étaient dominées par les vaisseaux spatiaux et les tirs de laser, un petit personnage rond et jaun...