À 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


