samedi 20 septembre 2025

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 jaune est arrivé pour tout changer. Oubliez les combats intergalactiques : Pac-Man a introduit une formule simple mais addictive qui a conquis le cœur de millions de joueurs. Bienvenue sur ArcadeForge, et préparez-vous à une plongée dans les coulisses de l'un des jeux les plus célèbres de tous les temps.

Le Jeu : Un Labyrinthe de Dangers et de Délices

Le principe de Pac-Man, sorti en 1980, est d'une simplicité désarmante. Le joueur contrôle Pac-Man, un cercle jaune à la bouche grande ouverte, dans un labyrinthe rempli de petites pac-gommes. Le but est de toutes les dévorer pour passer au niveau suivant.

Mais la simplicité s'arrête là. Quatre fantômes, chacun avec sa propre personnalité, sont à la poursuite de notre héros. Blinky le rouge, Pinky le rose, Inky le cyan et Clyde l'orange. Ces spectres sont redoutables, mais Pac-Man a une botte secrète : les "super pac-gommes" (ou "power pellets"). En les mangeant, il peut temporairement renverser la situation et dévorer ses poursuivants, marquant ainsi des points supplémentaires. Ce mélange de stratégie, de réflexes et de poursuite a rendu le jeu irrésistiblement amusant.

 


 

Le Cerveau Derrière le Labyrinthe

L'homme à l'origine de ce chef-d'œuvre est Toru Iwatani, un jeune designer de jeux vidéo travaillant pour l'entreprise japonaise Namco. Fatigué de l'omniprésence des jeux de guerre et de science-fiction, Iwatani voulait créer un jeu qui plairait également aux femmes et aux couples, en proposant quelque chose de non-violent et de mignon.

L'idée du personnage principal lui serait venue en observant une pizza à laquelle il manquait une part, donnant l'apparence d'une bouche. L'idée de manger les fantômes après avoir mangé les super pac-gommes est un clin d'œil à l'idée d'un "changement de rôle" entre le chasseur et le chassé.

Namco et le Phénomène Mondial

Sorti initialement au Japon sous le nom de "Puck-Man", le jeu a connu un succès modeste avant d'être exporté aux États-Unis par l'entreprise Midway Games. C'est là que "Puck-Man" a été rebaptisé "Pac-Man" pour éviter que le "P" ne soit transformé en "F" par des petits malins.

Le reste appartient à l'histoire. Pac-Man est devenu une véritable icône culturelle, générant un engouement sans précédent : produits dérivés, séries télévisées, chansons, et une popularité qui n'a jamais faibli. Le jeu a non seulement sauvé Namco de la faillite, mais il a également marqué la fin d'une époque et le début d'une autre dans le monde du jeu vidéo, prouvant qu'il n'était pas nécessaire de tirer pour s'amuser.

Pac-Man n'est pas seulement un jeu rétro, c'est un monument. Il incarne l'esprit d'innovation et la créativité de l'âge d'or de l'arcade.

 

Voici un projet complet en Love de Pacman : https://github.com/r-sede/lovePacMan 

ici la mécanique du jeu : 

 

 -- ============================
-- VARIABLES GLOBALES
-- ============================
-- Ces variables définissent les dimensions du jeu et d'autres paramètres essentiels.
 

PPM = 1 -- Pixels Per Meter, pour une gestion des dimensions
VW = 448 -- View Width, la largeur de la vue du jeu
VH = 576 -- View Height, la hauteur de la vue du jeu
BLOCKSIZE = 16 -- La taille en pixels d'un bloc de la grille, utilisée pour la map
MAP = nil -- La table qui contiendra la map du labyrinthe
MAPSHEET = {} -- Une table pour stocker les images des blocs de la map
FRUITSHEET = {} -- Une table pour stocker les images des fruits
MAPATLAS = nil -- L'image globale (atlas) des sprites de la map
FRUITATLAS = nil -- L'image globale (atlas) des sprites des fruits
DEBUG = false -- Active ou désactive le mode debug
DOTS = 244 -- Le nombre total de pac-gommes sur la map
PAUSE = false -- Indique si le jeu est en pause
TITLESCREEN = nil -- L'image de l'écran-titre
CURRENTSTATE = 'title' -- L'état actuel du jeu (titre, jeu, game over, etc.)
LEVEL = 1 -- Le niveau actuel
READYTIMER = 4.5 -- Le temps d'attente au début d'un niveau
FONT = nil -- La police de caractères pour l'affichage
HIGHSCORE = {} -- Une table pour stocker les meilleurs scores
CATCHPOINT = {200, 400, 800, 1600, 12000} -- Points gagnés en mangeant des fantômes (la valeur augmente pour chaque fantôme)
DEBUG_PLACEHOLDER = 0 -- Une variable pour ajuster la fenêtre en mode debug
SOUNDVOL = 1 -- Volume du son
S_INTRO, S_DOT, S_DEATH, S_EATGHOST, S_READY = nil -- Variables pour stocker les sons du jeu

-- ============================
-- FONCTION LOVE.LOAD
-- ============================
-- love.load est la fonction principale de LÖVE. Elle est exécutée une seule fois au démarrage du jeu.
function love.load(arg)
 

   -- Initialise la graine du générateur de nombres aléatoires
    love.math.setRandomSeed(love.timer.getTime())
 

   -- Définit le filtre des graphismes sur 'nearest' pour un effet pixel art net
    love.graphics.setDefaultFilter('nearest')
    -- Active la répétition des touches du clavier (pratique pour le mouvement)
    love.keyboard.setKeyRepeat(true)

    -- Importe les modules Lua contenant la logique du jeu
    require"pacMan" -- Logique du joueur (mouvement, collisions)
    require"ghosts" -- Logique et intelligence artificielle des fantômes
    require"pacManStates" -- Gestion des états du jeu
    require"levelSpec" -- Spécifications des niveaux (fruits, etc.)
    getMaps = require('map') -- Fonction pour charger les cartes du labyrinthe

    -- Vérifie si le jeu a été lancé en mode debug
    if arg[#arg] == "-debug" then
        DEBUG_PLACEHOLDER = 300
        DEBUG = true
        print('\n')
    end

    -- Configure la taille de la fenêtre du jeu
    love.window.setMode((PPM * VW) + DEBUG_PLACEHOLDER, PPM * VH)
    love.window.setTitle('LovePacMan') -- Définit le titre de la fenêtre

    -- Charge la police de caractères
    FONT = love.graphics.newFont('assets/fonts/emulogic.ttf', 8)
    love.graphics.setFont(FONT)

    -- Charge les images et les divise en feuilles de sprites
    TITLESCREEN = love.graphics.newImage('assets/img/title.png')
    FRUITATLAS = love.graphics.newImage('assets/img/fruits.png')
    FRUITSHEET['cherries'] = love.graphics.newQuad(0 * 16, 0, 16, 16, FRUITATLAS:getDimensions())
    FRUITSHEET['strawberry'] = love.graphics.newQuad(1 * 16, 0, 16, 16, FRUITATLAS:getDimensions())
    FRUITSHEET['peach'] = love.graphics.newQuad(2 * 16, 0, 16, 16, FRUITATLAS:getDimensions())
    FRUITSHEET['apple'] = love.graphics.newQuad(3 * 16, 0, 16, 16, FRUITATLAS:getDimensions())
    FRUITSHEET['grapes'] = love.graphics.newQuad(4 * 16, 0, 16, 16, FRUITATLAS:getDimensions())
    FRUITSHEET['bell'] = love.graphics.newQuad(5 * 16, 0, 16, 16, FRUITATLAS:getDimensions())
    FRUITSHEET['galaxian'] = love.graphics.newQuad(6 * 16, 0, 16, 16, FRUITATLAS:getDimensions())
    FRUITSHEET['key'] = love.graphics.newQuad(6 * 16, 0, 16, 16, FRUITATLAS:getDimensions())

    MAPATLAS = love.graphics.newImage('assets/img/pacmanSpriteSheet.png')
    MAPSHEET[1] = love.graphics.newQuad(0 * 16, 0, 16, 16, MAPATLAS:getDimensions())
    MAPSHEET[2] = love.graphics.newQuad(1 * 16, 0, 16, 16, MAPATLAS:getDimensions())
    MAPSHEET[3] = love.graphics.newQuad(2 * 16, 0, 16, 16, MAPATLAS:getDimensions())
    MAPSHEET[4] = love.graphics.newQuad(3 * 16, 0, 16, 16, MAPATLAS:getDimensions())
    MAPSHEET[5] = love.graphics.newQuad(4 * 16, 0, 16, 16, MAPATLAS:getDimensions())
    MAPSHEET[6] = love.graphics.newQuad(5 * 16, 0, 16, 16, MAPATLAS:getDimensions())
    MAPSHEET[9] = love.graphics.newQuad(6 * 16, 0, 16, 16, MAPATLAS:getDimensions())
    MAPSHEET[8] = love.graphics.newQuad(7 * 16, 0, 16, 16, MAPATLAS:getDimensions())

    -- Charge les sons du jeu
    S_INTRO = love.audio.newSource('assets/sfx/pacman_beginning.wav', 'static')
    S_DOT = love.audio.newSource('assets/sfx/pacman_chomp.wav', 'static')
    S_DEATH = love.audio.newSource('assets/sfx/pacman_death.wav', 'static')
    S_EATGHOST = love.audio.newSource('assets/sfx/pacman_eatghost.wav', 'static')
    S_EATFRUIT = love.audio.newSource('assets/sfx/pacman_eatfruit.wav', 'static')
    S_READY = love.audio.newSource('assets/sfx/pacman_intermission.wav', 'static')
    S_EXTRA = love.audio.newSource('assets/sfx/pacman_extrapac.wav', 'static')

    getHighScore() -- Récupère les meilleurs scores sauvegardés
    S_INTRO:play() -- Démarre la musique d'introduction
end

-- ============================
-- BOUCLE DE JEU
-- ============================
 

-- Ces fonctions sont appelées en continu pendant l'exécution du jeu.
function love.update(dt) -- Met à jour la logique du jeu
    if PAUSE then return end -- Si le jeu est en pause, rien ne se passe
    pacMan_states[CURRENTSTATE].update(dt) -- Appelle la fonction de mise à jour pour l'état actuel
end

function love.draw() -- Dessine tous les éléments à l'écran
    pacMan_states[CURRENTSTATE].draw() -- Appelle la fonction de dessin pour l'état actuel
end

function love.keypressed(key, scancode, isRepeat) -- Gère les entrées clavier
    if key == 'm' then
        if SOUNDVOL == 1 then SOUNDVOL = 0 else SOUNDVOL = 1 end
        love.audio.setVolume(SOUNDVOL) -- Active/désactive le son
    end
    pacMan_states[CURRENTSTATE].keypressed(key) -- Gère l'entrée clavier pour l'état actuel
end

-- ============================
-- FONCTIONS D'AFFICHAGE ET UTILITAIRES
-- ============================
 

function drawMap() -- Dessine le labyrinthe et les éléments de jeu
    -- Boucles pour parcourir la map
    for j = 1, #MAP do
        for i = 1, #MAP[j] do
            ii = i - 1
            jj = j - 1
            local curChar = MAP[j][i]
            if curChar > 0 then
                -- Dessine les éléments du labyrinthe
                love.graphics.draw(MAPATLAS, MAPSHEET[curChar], ii * BLOCKSIZE * PPM, jj * BLOCKSIZE * PPM, 0, PPM, PPM)
            end
            local collectChar = COLLECTABLE[j][i]
            if collectChar > 0 then
                -- Dessine les pac-gommes et super pac-gommes
                love.graphics.draw(MAPATLAS, MAPSHEET[collectChar], ii * BLOCKSIZE * PPM, jj * BLOCKSIZE * PPM, 0, PPM, PPM)
            end
            local fruitChar = FRUIT[j][i]
            if fruitChar > 0 then
                -- Dessine les fruits bonus
                love.graphics.draw(
                    FRUITATLAS, FRUITSHEET[levelSpec[LEVEL].bonus],
                    ii * BLOCKSIZE * PPM + BLOCKSIZE * PPM * 0.5,
                    jj * BLOCKSIZE * PPM + BLOCKSIZE * PPM * 0.5,
                    0, PPM * 1.6, PPM * 1.6,
                    16 * 0.5, 16 * 0.5
                )
            end
        end
    end

    if (DEBUG) then -- Affichage de debug pour les développeurs
        for j = 1, #MAP do
            for i = 1, #MAP[j] do
                ii = i - 1
                jj = j - 1
                local curChar = MAP[j][i]
                if curChar > 0 then
                    love.graphics.print(curChar, ii * BLOCKSIZE * PPM, jj * BLOCKSIZE * PPM)
                    love.graphics.rectangle("line", ii * BLOCKSIZE * PPM, jj * BLOCKSIZE * PPM, PPM * BLOCKSIZE, PPM * BLOCKSIZE)
                end
            end
        end
    end
end

function animate(this, dt) -- Gère l'animation des sprites (Pac-Man et fantômes)
    this.animTimer = this.animTimer - dt
    if this.animTimer <= 0 then
        this.animTimer = 1 / this.fps
        this.keyframe = this.keyframe + 1
        if this.keyframe > this.nbrFrame then this.keyframe = 1 end
    end
end

function handleDirection(this) -- Gère l'orientation du personnage
    if this.direction == 'left' then
        this.scaleSignX = -1
        this.scaleSignY = 1
        this.angle = 0
    elseif this.direction == 'right' then
        this.scaleSignX = -1
        this.scaleSignY = -1
        this.angle = math.pi
    elseif this.direction == 'up' and this == pacMan then
        this.scaleSignX = -1
        this.scaleSignY = 1
        this.angle = math.pi * 0.5
    elseif this.direction == 'down' and this == pacMan then
        this.scaleSignX = -1
        this.scaleSignY = 1
        this.angle = math.pi * 3 * 0.5
    end
end

function round(val) -- Fonction pour arrondir un nombre
    local floor = math.floor(val)
    if (val % 1 >= 0.5) then return floor + 1 end
    return floor
end

function clamp(val, min, max) -- Limite une valeur dans un intervalle
    if val < min then return min
    elseif val > max then return max
    else return val
    end
end

function writeScore() -- Écrit le score dans un fichier
    local tmp = {}
    tmp[1] = pacMan.score
    for i = 1, #HIGHSCORE do
        table.insert(tmp, HIGHSCORE[i])
    end
    local res = ''
    for i = 1, #tmp do
        res = res .. tmp[i] .. '\n'
    end
    local f = io.open('highscore.score', 'w+')
    f:write(res)
    f:close()
end

function fileExists(name) -- Vérifie l'existence d'un fichier
    local f = io.open(name, "r")
    if f ~= nil then io.close(f) return true else return false end
end

function linesFrom(file) -- Lit un fichier ligne par ligne
    if not fileExists(file) then return {0} end
    lines = {}
    for line in io.lines(file) do
        lines[#lines + 1] = tonumber(line)
    end
    return lines
end

function getHighScore() -- Récupère les scores enregistrés
    if fileExists('highscore.score') then
        HIGHSCORE = linesFrom('highscore.score')
    else
        local f = io.open('highscore.score', 'w')
        f:write('0')
        f:close()
        HIGHSCORE = {0}
    end
end 

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...