Pacman

The program Python
​
###
#Projet PACMAN :Eden et Lyna
###
import pyxel
import random
class PacmanGame:
###################################################
# Initialiser toutes les valeurs
###################################################
def __init__(self):
self.width = 160
self.height = 120
self.cell_size = 10
self.grid_width = self.width // self.cell_size
self.grid_height = self.height // self.cell_size
self.pacman_x = 80
self.pacman_y = 80
self.pacman_radius = 5
self.velocity = 2
self.direction = None
self.score = 0
self.game_state = "playing" # alternarive :"game_over"
# PREMMIER FANTOME
self.ghost_x = 80
self.ghost_y = 100
self.ghost_velocity = 1
self.ghost_direction = random.choice(['left', 'right', 'up', 'down'])
# SECOND FANTOME
self.following_ghost_x = 40
self.following_ghost_y = 40
self.following_ghost_direction = 'left'
# TROISIEM FANTOME
self.Dernier_ghost_x = 100
self.Dernier_ghost_y = 30
self.Dernier_ghost_direction = 'left' # Initial direction
self.Dernier_ghost_velocity = 1.5 # The ghost's movement speed
# Compte 60 images a 30 par secondes = 2s
self.ghost_active = False # Initial state for the first ghost
self.following_ghost_active = False # Initial state for the second ghost
self.Dernier_ghost_active = False # Initial state for the second ghost
# 3 vies POUR COMMENCER
self.lives = 3
# Définir restTime
self.restTime = 0
######################################################
# CREATION DE LA GRILLE "ON THE FLY" (PAS DE FICHIER) après avoir essayé de supperposé des matrices pour donner à chaque case un statut différent
# en fonction de la position de PACMAN et celle des FANTOMES nous avons décider d'utiliser une bibliothèque.
######################################################
self.grid = {x: {y: {'isWall': False, 'containsPill': False} for y in range(self.grid_height)} for x in range(self.grid_width)}
for x in range(self.grid_width):
for y in range(self.grid_height):
if not self.grid[x][y]['isWall']: # Si isWall est False
self.grid[x][y]['containsPill'] = True # Alors containsPill devient True (Cela nous évite d'avoir à placer les pionts un à un)
# Ajouter le murs
#Horizintal
for xl in range(0,17):
self.add_wall(xl, 0)
self.add_wall(xl, 11)
if not xl == 7 and not xl == 1 and not xl == 14 and not xl == 8: # Exclut à la fois 1 et 5
self.add_wall(xl, 6)
if not xl == 3 and not xl == 1 and not xl == 14 and not xl == 12: # Exclut à la fois 1 et 5
self.add_wall(xl, 2)
#Vertical
for xl in range(0,13):
self.add_wall(0, xl)
self.add_wall(15,xl)
if not xl == 1 and not xl == 10 and not xl == 5 and not xl == 7: # Exclut à la fois 1 et 5
self.add_wall(2, xl)
if not xl == 1 and not xl == 10 and not xl == 5 and not xl == 7: # Exclut à la fois 1 et 5
self.add_wall(13, xl)
#Point d'apparition des fantomes
if not xl == 1 and not xl == 2 and not xl == 5 and not xl == 7 and not xl == 3 and not xl == 4: # Exclut à la fois 1 et 5
self.add_wall(5, xl)
if not xl == 1 and not xl == 2 and not xl == 5 and not xl == 7 and not xl == 3 and not xl == 4: # Exclut à la fois 1 et 5
self.add_wall(10, xl)
# On ajoute "manuellement" des cube et une bille qui nous a servi de test
self.add_pill(7, 7)
self.add_wall(6, 5)
self.add_wall(9, 4)
self.add_wall(6, 4)
self.add_wall(9, 5)
pyxel.init(self.width, self.height)
pyxel.run(self.update, self.draw)
def add_wall(self, x, y):
if 0 <= x < self.grid_width and 0 <= y < self.grid_height:
self.grid[x][y]['isWall'] = True
def add_pill(self, x, y):
if 0 <= x < self.grid_width and 0 <= y < self.grid_height:
self.grid[x][y]['containsPill'] = True
def update_ghost(self):
# On propose aux fantome une nouvelle direction
next_x, next_y = self.ghost_x, self.ghost_y
if self.ghost_direction == 'left':
next_x -= self.ghost_velocity
elif self.ghost_direction == 'right':
next_x += self.ghost_velocity
elif self.ghost_direction == 'up':
next_y -= self.ghost_velocity
elif self.ghost_direction == 'down':
next_y += self.ghost_velocity
# La prochaine position est ensuite convertie en coordonnées (liées à la grille)
grid_x, grid_y = next_x // self.cell_size, next_y // self.cell_size
# On check la collision des parois
if 0 <= grid_x < self.grid_width and 0 <= grid_y < self.grid_height and not self.grid[grid_x][grid_y]['isWall']:
# Si aucune collision alors changer position fantome
self.ghost_x, self.ghost_y = next_x, next_y
else:
# Si collision alors choisir une nouvelle direction
self.choose_new_direction()
#On va maintenant coder un le following ghost, un fantome qui suit les déplacement de PACMAN
def update_following_ghost(self):
directions = ['left', 'right', 'up', 'down']
min_distance = float('inf')
selected_direction = self.following_ghost_direction
for direction in directions:
dx, dy = self.following_ghost_x, self.following_ghost_y
if direction == 'left':
dx -= self.ghost_velocity
elif direction == 'right':
dx += self.ghost_velocity
elif direction == 'up':
dy -= self.ghost_velocity
elif direction == 'down':
dy += self.ghost_velocity
grid_x, grid_y = dx // self.cell_size, dy // self.cell_size
if 0 <= grid_x < self.grid_width and 0 <= grid_y < self.grid_height and not self.grid[grid_x][grid_y]['isWall']:
distance = abs(dx - self.pacman_x) + abs(dy - self.pacman_y) # Manhattan distance
if distance < min_distance:
min_distance = distance
selected_direction = direction
self.following_ghost_direction = selected_direction
# Pour bouger le fantome vers PM
if self.following_ghost_direction == 'left':
self.following_ghost_x -= self.ghost_velocity
elif self.following_ghost_direction == 'right':
self.following_ghost_x += self.ghost_velocity
elif self.following_ghost_direction == 'up':
self.following_ghost_y -= self.ghost_velocity
elif self.following_ghost_direction == 'down':
self.following_ghost_y += self.ghost_velocity
#On crée maintenant un dernier fantome, le meme que le précédent sauf que ce dernier est plus rapide (une velocity 50% supperieure)
def update_Dernier_ghost(self):
directions = ['left', 'right', 'up', 'down']
min_distance = float('inf')
selected_direction = self.Dernier_ghost_direction
for direction in directions:
dx, dy = self.Dernier_ghost_x, self.Dernier_ghost_y
if direction == 'left':
dx -= self.Dernier_ghost_velocity
elif direction == 'right':
dx += self.Dernier_ghost_velocity
elif direction == 'up':
dy -= self.Dernier_ghost_velocity
elif direction == 'down':
dy += self.Dernier_ghost_velocity
grid_x, grid_y = dx // self.cell_size, dy // self.cell_size
if 0 <= grid_x < self.grid_width and 0 <= grid_y < self.grid_height and not self.grid[grid_x][grid_y]['isWall']:
distance = abs(dx - self.pacman_x) + abs(dy - self.pacman_y) # Manhattan distance
if distance < min_distance:
min_distance = distance
selected_direction = direction
self.Dernier_ghost_direction = selected_direction
# Pour bouger le fantome vers PM
if self.Dernier_ghost_direction == 'left':
self.Dernier_ghost_x -= self.Dernier_ghost_velocity
elif self.Dernier_ghost_direction == 'right':
self.Dernier_ghost_x += self.Dernier_ghost_velocity
elif self.Dernier_ghost_direction == 'up':
self.Dernier_ghost_y -= self.Dernier_ghost_velocity
elif self.Dernier_ghost_direction == 'down':
self.Dernier_ghost_y += self.Dernier_ghost_velocity
def choose_new_direction(self):
directions = ['left', 'right', 'up', 'down']
opposite_direction = {'left': 'right', 'right': 'left', 'up': 'down', 'down': 'up'}
directions.remove(opposite_direction[self.ghost_direction]) # Enlever la direction opposée
self.ghost_direction = random.choice(directions)
def update(self):
if self.game_state == "game_over":
if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT):
mouse_x, mouse_y = pyxel.mouse_x, pyxel.mouse_y
if (self.replay_button_x <= mouse_x <= self.replay_button_x + self.replay_button_width and
self.replay_button_y <= mouse_y <= self.replay_button_y + self.replay_button_height):
self.reset_game() # On réinitialise le jeu
elif self.game_state == "playing":
next_x = self.pacman_x + {'left': -self.velocity, 'right': self.velocity}.get(self.direction, 0)
next_y = self.pacman_y + {'up': -self.velocity, 'down': self.velocity}.get(self.direction, 0)
grid_x, grid_y = next_x // self.cell_size, next_y // self.cell_size
if 0 <= grid_x < self.grid_width and 0 <= grid_y < self.grid_height and not self.grid[grid_x][grid_y]['isWall']:
self.pacman_x, self.pacman_y = next_x, next_y
if self.grid[grid_x][grid_y].get('containsPill', False):
self.grid[grid_x][grid_y]['containsPill'] = False
self.score += 10 # Incrémentation du score lorsque PM mange une bille
if pyxel.btnp(pyxel.KEY_LEFT): self.direction = 'left'
elif pyxel.btnp(pyxel.KEY_RIGHT): self.direction = 'right'
elif pyxel.btnp(pyxel.KEY_UP): self.direction = 'up'
elif pyxel.btnp(pyxel.KEY_DOWN): self.direction = 'down'
# Activer chaque fantome toutes les 2 seconds (30 frames * 2)
# Update/Activer le premier fantome
if pyxel.frame_count > (self.restTime+60):
self.ghost_active = True
if self.ghost_active: self.update_ghost() # Premier fantome
# Update/Activer le deuxième fantome
if pyxel.frame_count > (self.restTime+120):
self.following_ghost_active = True
if self.following_ghost_active: self.update_following_ghost()
# Update/Activer le troisieme fantome
if pyxel.frame_count > (self.restTime+180):
self.Dernier_ghost_active = True
if self.Dernier_ghost_active: self.update_Dernier_ghost()
# Ici on améliore la colision des fantomes avec les murs suite à quelque problèmes ultérieurs dues au coté choisis pour dessiner les fantomes
if self.ghost_active:
dx = self.pacman_x - self.ghost_x
dy = self.pacman_y - self.ghost_y
distance = (dx ** 2 + dy ** 2) ** 0.5 # On calcule la distance entre les centres
if distance < 0.9 * self.pacman_radius:
self.lives -= 1 # PM perd une vie
if self.lives > 0:
self.reset_positions() # On réinitialise le jeu lorsqu'une vie est perdue
else:
self.game_over() # Fin de la partie si PM n'a plus de vies
# fantome 2
if self.following_ghost_active:
dx = self.pacman_x - self.following_ghost_x
dy = self.pacman_y - self.following_ghost_y
distance = (dx ** 2 + dy ** 2) ** 0.5 # On calcule la distance entre les centres
if distance < 0.9 * self.pacman_radius:
self.lives -= 1 # PM perd une vie
if self.lives > 0:
self.reset_positions() # On réinitialise le jeu lorsqu'une vie est perdue
else:
self.game_over() # Fin de la partie si PM n'a plus de vies
# On réitère pour le fantome 3
if self.Dernier_ghost_active:
dx = self.pacman_x - self.Dernier_ghost_x
dy = self.pacman_y - self.Dernier_ghost_y
distance = (dx ** 2 + dy ** 2) ** 0.5
if distance < 0.9 * self.pacman_radius:
self.lives -= 1
if self.lives > 0:
self.reset_positions()
else:
self.game_over()
# La victoire si le joueur atteint 1020 points car il y a 102 billes
if self.score >= 1020:
self.game_state = "victory"
def draw_pacman(self):
# On dessine PM
pyxel.circ(self.pacman_x, self.pacman_y, self.pacman_radius, pyxel.COLOR_YELLOW)
# Oeuil de PM
eye_x, eye_y = self.pacman_x + 2, self.pacman_y - 3
pyxel.circ(eye_x, eye_y, 1, pyxel.COLOR_BLACK)
# Bouche de PM
if self.direction == "right":
pyxel.tri(self.pacman_x, self.pacman_y, self.pacman_x + 5, self.pacman_y - 5, self.pacman_x + 5, self.pacman_y + 5, pyxel.COLOR_BLACK)
elif self.direction == "left":
pyxel.tri(self.pacman_x, self.pacman_y, self.pacman_x - 5, self.pacman_y - 5, self.pacman_x - 5, self.pacman_y + 5, pyxel.COLOR_BLACK)
elif self.direction == "up":
pyxel.tri(self.pacman_x, self.pacman_y, self.pacman_x - 5, self.pacman_y - 5, self.pacman_x + 5, self.pacman_y - 5, pyxel.COLOR_BLACK)
elif self.direction == "down":
pyxel.tri(self.pacman_x, self.pacman_y, self.pacman_x - 5, self.pacman_y + 5, self.pacman_x + 5, self.pacman_y + 5, pyxel.COLOR_BLACK)
def draw_ghost(self, x, y, color):
# Dessin de fantome
pyxel.circb(x, y, self.pacman_radius, color)
for offset in range(-self.pacman_radius, self.pacman_radius + 1, 3):
pyxel.line(x + offset, y + self.pacman_radius - 1, x + offset, y + self.pacman_radius + 2, color)
# Oeuil des fantomes
pyxel.circ(x - 2, y - 1, 1, pyxel.COLOR_WHITE)
pyxel.circ(x + 2, y - 1, 1, pyxel.COLOR_WHITE)
pyxel.pset(x - 2, y - 1, pyxel.COLOR_BLACK)
pyxel.pset(x + 2, y - 1, pyxel.COLOR_BLACK)
def draw(self):
if self.game_state == "playing":
pyxel.cls(0)
self.draw_pacman()
for x in range(self.grid_width):
for y in range(self.grid_height):
cell = self.grid[x][y]
if cell['isWall']:
pyxel.rect(x * self.cell_size, y * self.cell_size, self.cell_size, self.cell_size, pyxel.COLOR_NAVY)
elif cell['containsPill']:
pill_x, pill_y = x * self.cell_size + self.cell_size // 2, y * self.cell_size + self.cell_size // 2
pyxel.circ(pill_x, pill_y, 2, pyxel.COLOR_WHITE)
# Dessiner le score
pyxel.text(5, 5, f"Score: {self.score}", pyxel.COLOR_WHITE)
# Dessiner premier fantome
if self.ghost_active:
self.draw_ghost(self.ghost_x, self.ghost_y, pyxel.COLOR_RED)
# Dessiner le fantome qui suit
if self.following_ghost_active:
self.draw_ghost(self.following_ghost_x, self.following_ghost_y, pyxel.COLOR_GREEN)
# Dessiner le fantome rapide
if self.Dernier_ghost_active:
self.draw_ghost(self.Dernier_ghost_x, self.Dernier_ghost_y, pyxel.COLOR_DARK_BLUE)
elif self.game_state == "game_over":
# Dessiner le "Game Over"
pyxel.text(self.width // 2 - 20, self.height // 2 - 10, "Game Over!", pyxel.COLOR_RED)
elif self.game_state == "victory":
pyxel.cls(0) # Effacer l'écran
pyxel.text(self.width // 2 - 20, self.height // 2, "Victoire!", pyxel.COLOR_YELLOW)
# Dessiner les coeurs
for i in range(self.lives):
heart_x = self.width - (i + 1) * 16 - 5 # Position hearts from right to left
heart_y = 5
# Dessiner deux cercles
pyxel.circ(heart_x + 3, heart_y + 3, 3, pyxel.COLOR_RED)
pyxel.circ(heart_x + 8, heart_y + 3, 3, pyxel.COLOR_RED)
# Dessiner un triangle à l'envers pour le bas du coeur
pyxel.tri(heart_x, heart_y + 3, heart_x + 11, heart_y + 3, heart_x + 5.5, heart_y + 10, pyxel.COLOR_RED)
def game_over(self):
self.game_state = "game_over"
def reset_game(self):
# On réinitialise les éléments du jeux
self.pacman_x = 80
self.pacman_y = 80
self.ghost_x = 80
self.ghost_y = 100
self.following_ghost_x = 40
self.following_ghost_y = 40
self.Dernier_ghost_x = 100
self.Dernier_ghost_y = 30
self.score = 0
self.game_state = "playing"
def reset_positions(self):
# On réinitialise les éléments du jeux
self.pacman_x = 80
self.pacman_y = 80
self.ghost_x = 80
self.ghost_y = 100
self.following_ghost_x = 40
self.following_ghost_y = 40
self.Dernier_ghost_x = 100
self.Dernier_ghost_y = 30
self.ghost_active = False
self.following_ghost_active = False
self.Dernier_ghost_active = False
self.restTime = pyxel.frame_count
PacmanGame()
PACMAN.VF.py
Displaying PACMAN.VF.py.