diff --git a/Code/Mijn.mp3 b/Code/Mijn.mp3
new file mode 100644
index 0000000..6622150
Binary files /dev/null and b/Code/Mijn.mp3 differ
diff --git a/Code/__pycache__/entities.cpython-313.pyc b/Code/__pycache__/entities.cpython-313.pyc
index 792239a..a675513 100644
Binary files a/Code/__pycache__/entities.cpython-313.pyc and b/Code/__pycache__/entities.cpython-313.pyc differ
diff --git a/Code/__pycache__/group.cpython-313.pyc b/Code/__pycache__/group.cpython-313.pyc
index ee3708f..1c09205 100644
Binary files a/Code/__pycache__/group.cpython-313.pyc and b/Code/__pycache__/group.cpython-313.pyc differ
diff --git a/Code/__pycache__/settings.cpython-313.pyc b/Code/__pycache__/settings.cpython-313.pyc
index b0a4d52..99d2cbf 100644
Binary files a/Code/__pycache__/settings.cpython-313.pyc and b/Code/__pycache__/settings.cpython-313.pyc differ
diff --git a/Code/__pycache__/sprites.cpython-313.pyc b/Code/__pycache__/sprites.cpython-313.pyc
index 4f47db3..ec737b5 100644
Binary files a/Code/__pycache__/sprites.cpython-313.pyc and b/Code/__pycache__/sprites.cpython-313.pyc differ
diff --git a/Code/__pycache__/support.cpython-313.pyc b/Code/__pycache__/support.cpython-313.pyc
index 3cb2b25..43a77af 100644
Binary files a/Code/__pycache__/support.cpython-313.pyc and b/Code/__pycache__/support.cpython-313.pyc differ
diff --git a/Code/debug.py b/Code/debug.py
index 1ef1a88..5b7729c 100644
--- a/Code/debug.py
+++ b/Code/debug.py
@@ -1,10 +1,11 @@
-import pygame
-pygame.init()
-font = pygame.font.Font(None,30)
+import pygame #importation de pygame
+pygame.init() #initialisation de pygame pour pouvoir l'utiliser
+font = pygame.font.Font(None,30) #création d'un objet de police(font) avec une taille de 30, sans police spécifique
def debug(info,y = 10, x = 10):
- display_surface = pygame.display.get_surface()
- debug_surf = font.render(str(info),True,'White')
- debug_rect = debug_surf.get_rect(topleft = (x,y))
- pygame.draw.rect(display_surface,'Black',debug_rect)
- display_surface.blit(debug_surf,debug_rect)
+ #fonction qui affiche un texte de débogage sur la surface d'affichage
+ display_surface = pygame.display.get_surface() #récupere la surface d'affichage actuelle
+ debug_surf = font.render(str(info),True,'White') #crée une surface contenant le texte de débogage, en blanc
+ debug_rect = debug_surf.get_rect(topleft = (x,y)) # crée un rectangle autour du texte pour la positionner à (x,y)
+ pygame.draw.rect(display_surface,'Black',debug_rect) #dessine un rectangle noir autour du texte pour le rendre lisibles dans tout les cas
+ display_surface.blit(debug_surf,debug_rect) #affiche la surface contenant le texte sur l'ecran
diff --git a/Code/entities.py b/Code/entities.py
index 03f4021..9f40d13 100644
--- a/Code/entities.py
+++ b/Code/entities.py
@@ -1,83 +1,125 @@
-import pygame.sprite
+import pygame.sprite #module pygame pour gérer les sprites
-from settings import *
+from settings import * #importation des paramètres globaux du jeu
+#classe de base pour toutes les entités interactives du jeu
class Entity(pygame.sprite.Sprite):
def __init__(self, pos, frames, groups, regard):
- super().__init__(groups)
- self.z = WORLD_LAYERS['main']
+ #initialise une entité génrérique
+ super().__init__(groups) #ajoute l'entité dans le monde
+ self.z = WORLD_LAYERS['main'] #niveau de profondeur pour le tri d'affichage
-
-
- #graphics
- self.frames_indice, self.frames = 0, frames
- self.regard = regard
+ #graphismes
+ self.frames_indice, self.frames = 0, frames #animation(index actuel et frames disponibles)
+ self.regard = regard #direction actuelle de l'entité
# Mouvemenent :
- self.direction = vector()
- self.speed = 1000
-
- # sprite setup
- self.image = self.frames['down'][self.frames_indice]
- self.rect = self.image.get_frect(center = pos)
+ self.direction = vector() #direction de déplacement(vector2)
+ self.speed = 500 #vitesse de déplacement
+ self.blocked = False #indique si l'entité est bloquée (imobilisée)
+
+ # configuration du sprite
+ self.image = self.frames['down'][self.frames_indice] #image initiale (face vers le bas)
+ self.rect = self.image.get_frect(center = pos) # rectangle de position basé sur l'image
+ #ajuste la hitbox pour correspondre à la taille réelle de l'entité
self.hitbox = self.rect.inflate(-self.rect.width / 2, -60)
- self.y_sort = self.rect.centery
+ self.y_sort = self.rect.centery #utilisé pour trier les entités par profondeur
def animation(self,dt):
- self.frames_indice += ANIMATION_SPEED * dt
+ #anime l'entité en fonction de temps écoulé
+ self.frames_indice += ANIMATION_SPEED * dt #avance dans l'animation
+ #definit l'image actuelle en fonction de l'état et de l'animation en cours
self.image = self.frames[self.get_etat()][int(self.frames_indice % len(self.frames[self.get_etat()]))]
def get_etat(self):
+ # Déterminez l'état actuel de l'entité en fonction de son mouvement et de sa direction
+ #determine si l'entité est en mouvement
moving = bool(self.direction)
- if moving:
- if self.direction.x != 0:
- self.regard = 'right' if self.direction.x > 0 else 'left'
- if self.direction.y != 0:
- self.regard = 'down' if self.direction.y > 0 else 'up'
- return f"{self.regard}{'' if moving else '_idle'}"
+ # Définissez la direction basée sur le mouvement
+ if moving:
+ if self.direction.x > 0:
+ self.regard = 'right'
+ elif self.direction.x < 0:
+ self.regard = 'left'
+ elif self.direction.y > 0:
+ self.regard = 'down'
+ elif self.direction.y < 0:
+ self.regard = 'up'
+
+ # Genere l'etat actuel
+ etat = f"{self.regard}{'' if moving else '_idle'}"
+
+ # Vérifiez si l'état est valide
+ if etat not in self.frames:
+ print(f"Warning: Invalid state '{etat}' for character.") #avertissement si l'état est invalide
+ return f"{self.regard}_idle" # Retournez un état par défaut valide
+
+ return etat
+
+ def block(self):
+ #bloque l'entité, l'empêchant de bouger
+ self.blocked = True
+ self.direction = vector(0,0) #rénitialise la direction
+
+ def unblock(self):
+ #débloque l'entité, lui permetttant de bouger à nouveau
+ self.blocked = False
+
+#classe représentant un drésseur, nune entité spécialisée
class Dresseur(Entity):
def __init__(self, pos, frames, groups, regard):
+ #initialise un dresseur
super().__init__(pos, frames,groups, regard)
+#classe représentant le joueur une entité CONTROLABLE
class Player(Entity):
def __init__(self, pos, frames, groups, regard, collision_sprites):
+ #initialise le joueur
super().__init__(pos, frames, groups, regard)
- self.collision_sprites = collision_sprites
+ self.collision_sprites = collision_sprites #liste des objets avec lesquels le joueur peut entrer en collision
def input(self):
- keys = pygame.key.get_pressed()
- input_vector = vector()
+ #gere les entrées utilisateur pour définir la direction de déplacement
+ keys = pygame.key.get_pressed() #verifie les touches pressées
+ input_vector = vector() #direction basée sur les entrées
if keys[pygame.K_UP]:
- input_vector.y -= 1
+ input_vector.y -= 1 #haut
if keys[pygame.K_DOWN]:
- input_vector.y += 1
+ input_vector.y += 1 # bas
if keys[pygame.K_LEFT]:
- input_vector.x -= 1
+ input_vector.x -= 1 # gauche
if keys[pygame.K_RIGHT]:
- input_vector.x += 1
- self.direction = input_vector
+ input_vector.x += 1 #droite
+ #normalise le vecteur de direction pour éviter les déplacements irréguliers
+ self.direction = input_vector.normalize() if input_vector else input_vector
def mouvement(self, dt):
+ #gère le déplacement du joueur en prenant en compte le temps et les collisions
+ #deplace horizontalement
self.rect.centerx += self.direction.x * self.speed * dt
self.hitbox.centerx = self.rect.centerx
self.collisions('horizontale')
+ #deplace verticalement
self.rect.centery += self.direction.y * self.speed * dt
self.hitbox.centery = self.rect.centery
self.collisions('verticale')
def collisions(self, axis):
+ #gère les collisions entre le joueur et les objets de collisions
for sprite in self.collision_sprites:
- if sprite.hitbox.colliderect(self.hitbox):
+ if sprite.hitbox.colliderect(self.hitbox): #detecte une collision
if axis == 'horizontale':
+ #corrige la position selon la direction horizontale
if self.direction.x > 0: # Déplacement à droite
self.hitbox.right = sprite.hitbox.left
if self.direction.x < 0: # Déplacement à gauche
self.hitbox.left = sprite.hitbox.right
self.rect.centerx = self.hitbox.centerx # Synchronisation
else:
+ #corrige la position selon la direction verticale
if self.direction.y > 0: # Déplacement vers le bas
self.hitbox.bottom = sprite.hitbox.top
if self.direction.y < 0: # Déplacement vers le haut
@@ -85,7 +127,9 @@ def collisions(self, axis):
self.rect.centery = self.hitbox.centery # Synchronisation
def update(self, dt):
- self.y_sort = self.rect.centery
- self.input()
- self.mouvement(dt)
- self.animation(dt)
+ #met a jour l'état du joueur à chaque frame
+ self.y_sort = self.rect.centery #mise a jour du tri
+ if not self.blocked: #si le joueur n'est pas bloqué
+ self.input() #gestion des entrées
+ self.mouvement(dt) #gestion des mouvements
+ self.animation(dt) #mise a jour de l'animation
diff --git a/Code/group.py b/Code/group.py
index b44d12f..5245985 100644
--- a/Code/group.py
+++ b/Code/group.py
@@ -1,28 +1,36 @@
import pygame.sprite
-from settings import *
-from support import import_image
-from entities import *
+from settings import * #importation de constantes et configurations
+from support import import_image #importation de la fonction pour charger une image
+from entities import * #importation des entités
+#classe allsprites qui hérite de pygame.sprite.group
class AllSprites(pygame.sprite.Group):
def __init__(self):
- super().__init__()
- self.display_surface = pygame.display.get_surface()
- self.offset = vector()
- self.ombre_surf = import_image('..', 'graphics', 'other', 'ombre')
+ super().__init__() #appel du constructeur parent pour initialiser un groupe d'entités
+ self.display_surface = pygame.display.get_surface() #recuperation de la surface d'affichage de la fenêtre
+ self.offset = vector() #initialisation de l'offset pour le déplacement de la vue
+ self.ombre_surf = import_image('..', 'graphics', 'other', 'ombre') # chargement de l'image d'ombre
+ #méthode pour dessiner les sprites à l'écran en fonction de la position du joueur
def draw(self, player_center):
- self.offset.x = -(player_center[0] - WINDOW_WIDTH /2)
- self.offset.y = -(player_center[1] - WINDOW_HEIGHT /2)
+ #calcul de l'offset pour centrer l'écran sur le joueur
+ self.offset.x = -(player_center[0] - WINDOW_WIDTH /2) #decalage x
+ self.offset.y = -(player_center[1] - WINDOW_HEIGHT /2)#decalage y
- bg_sprite = [sprite for sprite in self if sprite.z < WORLD_LAYERS['main']]
- main_sprite = sorted([sprite for sprite in self if sprite.z == WORLD_LAYERS['main']], key=lambda sprite: sprite.y_sort)
- fg_sprite = [sprite for sprite in self if sprite.z > WORLD_LAYERS['main']]
+ #séparation des sprites selon leur profondeur dans le monde (couches)
+ bg_sprite = [sprite for sprite in self if sprite.z < WORLD_LAYERS['main']] #sprites d'arrière plan
+ main_sprite = sorted([sprite for sprite in self if sprite.z == WORLD_LAYERS['main']], key=lambda sprite: sprite.y_sort) #sprites principaux triés par position verticale
+ fg_sprite = [sprite for sprite in self if sprite.z > WORLD_LAYERS['main']] #sprites au premier plan
+ #dessin des sprites par couche
for layer in (bg_sprite, main_sprite, fg_sprite):
for sprite in layer:
+ #si le sprite est un joueur, on lui ajoute une ombre
if isinstance(sprite, Player):
self.display_surface.blit(self.ombre_surf, sprite.rect.topleft + self.offset + vector(25, 120))
+ #si le sprite est un dresseur, on lui ajoute aussi une ombre
if isinstance(sprite, Dresseur):
self.display_surface.blit(self.ombre_surf, sprite.rect.topleft + self.offset + vector(40, 110))
+ #dessine le sprite à l'ecran
self.display_surface.blit(sprite.image, sprite.rect.topleft + self.offset)
\ No newline at end of file
diff --git a/Code/main.py b/Code/main.py
index 20d5d27..061bc48 100644
--- a/Code/main.py
+++ b/Code/main.py
@@ -1,4 +1,5 @@
-from Code.sprites import Waremon_patch_Sprite
+from support import play_music
+from sprites import Waremon_patch_Sprite
from settings import *
from pytmx.util_pygame import load_pygame
from os.path import join
@@ -9,21 +10,42 @@
class Game:
def __init__(self):
+ #initialisation de pygame et configuration de la fenêtre principale
pygame.init()
self.display_surface = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption('Waremon')
self.clock = pygame.time.Clock()
- #groupes :
- self.all_sprites = AllSprites()
- self.collision_sprites = pygame.sprite.Group()
-
+ #groupes de sprites pour organiser les entités du jeu:
+ self.all_sprites = AllSprites() # tous les sprites
+ self.collision_sprites = pygame.sprite.Group() #sprites avec collision
+ self.character_sprites = pygame.sprite.Group() #sprites de personnages
+ self.transition_sprites = pygame.sprite.Group() #sprites de transition
+
+ #paramètres pour les transitions entre zones
+ self.transition_target = None #cible de la transition
+ self.tint_surf = pygame.Surface((WINDOW_WIDTH, WINDOW_HEIGHT)) #surface pour le fondu
+ self.tint_mode = 'untint' # mode de fondu
+ self.tint_progress = 0 #progression du fondu
+ self.tint_direction= -1 #direction du fondu(-1 pour retirer, +1 pour ajouter)
+ self.tint_speed = 600 # vitesse du fondu
+
+ #chargement des ressources et configuration initiales
self.import_assets()
self.setup(self.tmx_maps['map3'], 'house')
- def import_assets(self):
- self.tmx_maps = {'map3': load_pygame(join('..', 'data', 'maps', 'map3.tmx'))}
+ #lecture de la musique de fond
+ play_music("Mijn.mp3", volume=1)
+
+ def import_assets(self): #charge les cartes, animations
+ #chargement des cartes au format TMX
+ self.tmx_maps = {
+ 'map3' : load_pygame(join('..', 'data', 'maps', 'map3.tmx')),
+ 'plant' : load_pygame(join('..', 'data', 'maps', 'house.tmx')),
+ }
+
+ #chargement des frames pour les animations
self.overwolrd_frames = {
'water': import_folder(join('..', 'graphics', 'tilesets', 'water')),
'cote' : cote_importer(24,12,join('..', 'graphics', 'tilesets', 'cote')),
@@ -32,31 +54,46 @@ def import_assets(self):
# noinspection PyTypeChecker
- def setup(self, tmx_map, player_start_pos):
+ def setup(self, tmx_map, player_start_pos): #configure les sprites et entités pour une nouvelle carte
+ #réinitialisation des groupes de sprites
+ for group in (self.all_sprites, self.collision_sprites, self.transition_sprites, self.character_sprites):
+ group.empty()
+
# map 3 :
+ #chargement des différentes couches de la carte
for layer in ['Terrain', 'Terrain haut']:
for x, y, surf in tmx_map.get_layer_by_name(layer).tiles():
Sprite((x * TILE_SIZE, y * TILE_SIZE), surf, self.all_sprites, WORLD_LAYERS['bg'])
+ #ajout des animations pour les zones d'eau
for obj in tmx_map.get_layer_by_name('water'):
for x in range(int(obj.x), int(obj.x+obj.width), TILE_SIZE):
for y in range(int(obj.y), int(obj.y+obj.height), TILE_SIZE):
Animation((x,y), self.overwolrd_frames['water'], self.all_sprites, WORLD_LAYERS['water'])
+ #ajout des animations pour les côtes
for obj in tmx_map.get_layer_by_name('Côtes'):
terrain = obj.properties['terrain']
side = obj.properties['side']
Animation((obj.x, obj.y),self.overwolrd_frames['cote'][terrain][side], self.all_sprites, WORLD_LAYERS['bg'])
+ #création des objets avec collision
for obj in tmx_map.get_layer_by_name('Objets'):
CollidableSprite((obj.x, obj.y), obj.image, (self.all_sprites, self.collision_sprites))
+ #création des transitions entre zones
+ for obj in tmx_map.get_layer_by_name('Transitions'):
+ TransitionSprite((obj.x, obj.y),(obj.width,obj.height), (obj.properties['target'], obj.properties['pos']),self.transition_sprites)
+
+ #ajout des patches Waremon
for obj in tmx_map.get_layer_by_name('Herbe_ware'):
Waremon_patch_Sprite((obj.x, obj.y), obj.image, self.all_sprites)
+ #ajout des collisions pour les bordures
for obj in tmx_map.get_layer_by_name('Collisions'):
BorderSprite((obj.x, obj.y), pygame.Surface((obj.width, obj.height)), self.collision_sprites)
+ #création des entités (joueur et PNJ)
for obj in tmx_map.get_layer_by_name('Entités'):
if obj.name == 'Player':
if obj.properties['pos'] == player_start_pos:
@@ -71,17 +108,53 @@ def setup(self, tmx_map, player_start_pos):
Dresseur(
pos=(obj.x, obj.y),
frames=self.overwolrd_frames['characters'][obj.properties['graphic']],
- groups=( self.all_sprites, self.collision_sprites),
+ groups=( self.all_sprites, self.collision_sprites,self.character_sprites),
regard = obj.properties['direction']
)
-
-
- def run(self):
+ def input(self):#gère les entrées clavier du joueur, notamment l'interaction avec les persos
+ keys = pygame.key.get_just_pressed()
+ if keys[pygame.K_SPACE]:
+ for character in self.character_sprites:
+ if check_connection(100, self.player, character):
+ self.player.block()
+ #perso qui se regarde pendant dialogues
+ #character.change_facing_direction(self.player.rect.center)
+ #crée les dialogue
+ print('dialog')
+
+ #transition systeme
+ def transition_check(self):#verifie si le joueur entre dans une zone de transition
+ sprites = [sprite for sprite in self.transition_sprites if sprite.rect.colliderect(self.player.hitbox)]
+ if sprites:
+ self.player.block()
+ self.transition_target = sprites[0].target
+ self.tint_mode = 'tint'
+
+ def tint_screen(self,dt): #gère l'effet de fondu de l'écran lors des transitions.
+ if self.tint_mode == 'untint':
+ self.tint_progress -= self.tint_speed * dt
+ if self.tint_mode == 'tint' :
+ self.tint_progress += self.tint_speed * dt
+ if self.tint_progress >= 255:
+ #charger la nouvelle carte lorsque le fondu est terminé
+ self.setup(self.tmx_maps[self.transition_target[0]], self.transition_target[1])
+ self.tint_mode = 'untint'
+ self.transition_target = None
+
+ #limiter la progression du fondu entre 0 et 255
+ self.tint_progress = max(0, min(self.tint_progress, 255))
+ self.tint_surf.set_alpha(self.tint_progress)
+ self.display_surface.blit(self.tint_surf,(0,0))
+
+
+ def run(self): #boucle principale du jeu
while True:
+ #dessin des hitboxes de collision (debugging)
for sprite in self.collision_sprites:
pygame.draw.rect(self.display_surface, (255, 0, 0), sprite.hitbox, 2)
- dt = self.clock.tick() / 1000
+ dt = self.clock.tick() / 1000 #calcul du temps écoulé
+ #print(f"Available maps: {list(self.tmx_maps.keys())}") #debugging des cartes disponibles
#event boucle
for event in pygame.event.get():
if event.type == pygame.QUIT:
@@ -90,9 +163,14 @@ def run(self):
#game logique
+ self.input()
+ self.transition_check()
self.all_sprites.update(dt)
+ #affichage des éléments du jeu
self.display_surface.fill('Black')
self.all_sprites.draw(self.player.rect.center)
+
+ self.tint_screen(dt)
pygame.display.update()
if __name__ == '__main__':
diff --git a/Code/sprites.py b/Code/sprites.py
index 9accd42..80f4c59 100644
--- a/Code/sprites.py
+++ b/Code/sprites.py
@@ -1,37 +1,59 @@
-from settings import *
+from settings import * #importations des parametres globaux depuis le module settings
+#classe de base pour tous les sprites du jeu
class Sprite(pygame.sprite.Sprite):
def __init__(self, pos, surf, groups, z = WORLD_LAYERS['main']):
- super().__init__(groups)
- self.image = surf
- self.rect = self.image.get_frect(topleft = pos)
- self.z = z
- self.y_sort = self.rect.centery
- self.hitbox = self.rect.copy()
+ #initialise un sprite générique
+ super().__init__(groups) #ajoute ce sprite aux groupes spécifiés
+ self.image = surf #image ou surface graphique du sprite
+ self.rect = self.image.get_frect(topleft = pos) # rectangle de position basé sur la surface
+ self.z = z #niveau de profondeur pour le tri
+ self.y_sort = self.rect.centery # utilisé pour trier les sprites par leur position verticale
+ self.hitbox = self.rect.copy() #hitbox par défaut identique au rectangle graphique
+# sprite représentant une bordure, avec une hitbox par défaut
class BorderSprite(Sprite):
def __init__(self, pos, surf, groups):
+ #initialise un sprite de bordure.
super().__init__(pos, surf, groups)
self.hitbox = self.rect.copy()
+#sprite utilisé pour représenter les transitions entre zones
+class TransitionSprite(Sprite):
+ #initialise un sprite de transition
+ def __init__(self, pos, size, target, groups):
+ #surface transparente utilisée comme placeholder
+ surf = pygame.Surface(size)
+ super().__init__(pos, surf, groups)
+ self.target = target #destination de la transition (carte, position)
+
+#sprite interactif ayant une hitbox ajusté pour detecter les collisions
class CollidableSprite(Sprite):
def __init__(self, pos, surf, groups):
+ #initialise un sprite avec une hitbox ajustée pour les collisions
super().__init__(pos, surf, groups)
+ #la hitbox est réduite verticalement pour mieux correspondre à la taille réelle de l'objet
self.hitbox = self.rect.inflate(0, -self.rect.height * 0.4)
+#sprite représentant une zone d'herbe où des Waremons peuvent apparaître
class Waremon_patch_Sprite(Sprite):
+ #initialise une zone spéciale pour Waremons
def __init__(self, pos, surf, groups):
super().__init__(pos, surf, groups, WORLD_LAYERS['main'])
- self.y_sort -= 40
+ self.y_sort -= 40 #ajuste la position de tri vertical pour cet objet spécifique
+#sprite animé pouvant changer d'image à chaque frame
class Animation(Sprite):
+ #initialise un spritte animé
def __init__(self, pos, frames, groups, z = WORLD_LAYERS['main']):
- self.frames_indice, self.frames = 0, frames
+ self.frames_indice, self.frames = 0, frames #initialisation de l'indice et des frames
super().__init__(pos, frames[self.frames_indice],groups, z)
def animate(self, dt):
- self.frames_indice += ANIMATION_SPEED * dt
- self.image = self.frames[int(self.frames_indice % len(self.frames))]
+ #met à jour l'image de l'animation en fonction du temps écoulé
+ self.frames_indice += ANIMATION_SPEED * dt #incrémente l'indice en fonction de la vitesse
+ self.image = self.frames[int(self.frames_indice % len(self.frames))] #change l'image active
def update(self, dt):
- self.animate(dt)
\ No newline at end of file
+ #appelle la méthode d'animation pour chaque mise à jour
+ self.animate(dt) #met a jour l'animation
\ No newline at end of file
diff --git a/Code/support.py b/Code/support.py
index 1a88713..88e4915 100644
--- a/Code/support.py
+++ b/Code/support.py
@@ -3,13 +3,16 @@
from os import walk
from pytmx.util_pygame import load_pygame
-# imports
+# Fonction pour importer une image depuis un chemin donné
def import_image(*path, alpha = True, format = 'png'):
+ #charge une image avec ou sans transparence depuis un chemin donné
full_path = join(*path) + f'.{format}'
surf = pygame.image.load(full_path).convert_alpha() if alpha else pygame.image.load(full_path).convert()
return surf
+#fonction pour importer toutes les images d'un dossier
def import_folder(*path):
+ #charge toutes les images d'unn dossier, triées par leur nom
frames = []
for folder_path, sub_folders, image_names in walk(join(*path)):
for image_name in sorted(image_names, key = lambda name: int(name.split('.')[0])):
@@ -18,7 +21,9 @@ def import_folder(*path):
frames.append(surf)
return frames
+#fonction pour importer un dossier et créer un dictionnaire des images
def import_folder_dict(*path):
+ #charge toutes les images d'un dossier dans un dictionnaire, avec les noms des fichiers comme clés
frames = {}
for folder_path, sub_folders, image_names in walk(join(*path)):
for image_name in image_names:
@@ -27,7 +32,9 @@ def import_folder_dict(*path):
frames[image_name.split('.')[0]] = surf
return frames
+#fonction pour importer les sous-dossiers
def import_sub_folders(*path):
+ #charge les images contenues dans les sous-dossiers, organisées en dictionnaire.
frames = {}
for _, sub_folders, __ in walk(join(*path)):
if sub_folders:
@@ -35,7 +42,9 @@ def import_sub_folders(*path):
frames[sub_folder] = import_folder(*path, sub_folder)
return frames
+#fonction pour découper une sprite-sheet en tuiles
def import_tilemap(cols, rows, *path):
+ #decoupe une image en une grille de tuiles
frames = {}
surf = import_image(*path)
cell_width, cell_height = surf.get_width() / cols, surf.get_height() / rows
@@ -43,13 +52,15 @@ def import_tilemap(cols, rows, *path):
for row in range(rows):
cutout_rect = pygame.Rect(col * cell_width, row * cell_height,cell_width,cell_height)
cutout_surf = pygame.Surface((cell_width, cell_height))
- cutout_surf.fill('green')
- cutout_surf.set_colorkey('green')
+ cutout_surf.fill('green') #definir une couleur de fond pour le découpage
+ cutout_surf.set_colorkey('green') #rendre le fond transparent
cutout_surf.blit(surf, (0,0), cutout_rect)
frames[(col, row)] = cutout_surf
return frames
+#fonction pour importer une sprite-sheet pour un personnage
def character_importer(rows, cols, *path, image_name):
+ #découpe une sprite-sheet de personnage en animation par direction
# Charger la sprite-sheet
full_path = join(*path, f"{image_name}")
sprite_sheet = pygame.image.load(full_path).convert_alpha()
@@ -95,4 +106,46 @@ def cote_importer(cols, rows, *path):
new_dict[terrain] = {}
for key, pos in sides.items():
new_dict[terrain][key] = [frame_dict[(pos[0] + index * 3, pos[1]+ row)] for row in range(0, rows, 3)]
- return new_dict
\ No newline at end of file
+ return new_dict
+
+def tmx_importer(*path):
+ tmx_dict = {}
+ for folder_path, sub_folders, file_names in walk(join(*path)):
+ for file in file_names:
+ tmx_dict[file.split('.')[0]] = load_pygame(join(folder_path, file))
+ return tmx_dict
+
+
+#fonction jeu
+def check_connection(radius, entité, cible, tolerance = 30):
+ relation = vector(cible.rect.center) - vector(entité.rect.center)
+ if relation.length() < radius:
+ if entité.regard == 'left' and relation.x <0 and abs(relation.y) < tolerance or\
+ entité.regard == 'right' and relation.x > 0 and abs(relation.y) < tolerance or \
+ entité.regard == 'up' and relation.y < 0 and abs(relation.x) < tolerance or \
+ entité.regard == 'down' and relation.y > 0 and abs(relation.x) < tolerance:
+ return True
+
+def play_music(filepath, volume=0.5):
+ """
+ Charge et joue une musique en boucle.
+
+ :param filepath: Le chemin vers le fichier audio (format supporté par pygame).
+ :param volume: Volume de la musique (entre 0.0 et 1.0).
+ """
+ pygame.mixer.init() # Initialisation du mixer
+ pygame.mixer.music.load(filepath) # Charger le fichier audio
+ pygame.mixer.music.set_volume(volume) # Régler le volume
+ pygame.mixer.music.play(loops=-1) # Lecture en boucle infinie
+
+def pause_music():
+ """Met en pause la musique actuelle."""
+ pygame.mixer.music.pause()
+
+def resume_music():
+ """Reprend la musique après une pause."""
+ pygame.mixer.music.unpause()
+
+def stop_music():
+ """Arrête complètement la musique."""
+ pygame.mixer.music.stop()
diff --git a/Code/timer.py b/Code/timer.py
index 50fcd5b..91604cf 100644
--- a/Code/timer.py
+++ b/Code/timer.py
@@ -1,28 +1,34 @@
-from pygame.time import get_ticks
+from pygame.time import get_ticks # Importation de la fonction get_ticks de Pygame qui retourne le nombre de millisecondes écoulées depuis le lancement du jeu
+# Classe Timer permettant de gérer des minuteries (timers) avec des durées et des actions répétitives
class Timer:
+ # Initialisation de la minuterie avec des paramètres de durée, répétition, démarrage automatique et fonction à exécuter
def __init__(self, duration, repeat = False, autostart = False, func = None):
- self.duration = duration
- self.start_time = 0
- self.active = False
- self.repeat = repeat
- self.func = func
- if autostart:
+ self.duration = duration # Durée du timer en millisecondes
+ self.start_time = 0 # Temps de début, initialisé à 0
+ self.active = False # Le timer n'est pas actif au départ
+ self.repeat = repeat # Si True, le timer redémarrera une fois expiré
+ self.func = func # Fonction optionnelle à exécuter lorsque le timer expire
+ if autostart: # Si autostart est True, le timer démarre immédiatement
self.activate()
+ # Activation de la minuterie : elle devient active et on enregistre l'heure de départ
def activate(self):
- self.active = True
- self.start_time = get_ticks()
+ self.active = True # Le timer est maintenant actif
+ self.start_time = get_ticks() # Enregistre le temps actuel (en millisecondes) comme le temps de début du timer
+ # Désactivation de la minuterie : elle devient inactive et le temps de début est réinitialisé
def deactivate(self):
- self.active = False
- self.start_time = 0
- if self.repeat:
+ self.active = False # Le timer est désactivé
+ self.start_time = 0 # Réinitialisation du temps de départ
+ if self.repeat: # Si la minuterie est configurée pour se répéter, elle est réactivée
self.activate()
+ # Mise à jour de l'état de la minuterie à chaque frame
def update(self):
- if self.active:
- current_time = get_ticks()
- if current_time - self.start_time >= self.duration:
- if self.func: self.func()
- self.deactivate()
\ No newline at end of file
+ if self.active: # Si le timer est actif
+ current_time = get_ticks() # Récupère le temps actuel en millisecondes
+ if current_time - self.start_time >= self.duration: # Si le temps écoulé depuis le début dépasse la durée du timer
+ if self.func:# Si une fonction est définie pour être exécutée
+ self.func() # Appelle la fonction
+ self.deactivate() # Désactive le timer après avoir exécuté la fonction
\ No newline at end of file
diff --git a/Code/waremon_data.py b/Code/waremon_data.py
new file mode 100644
index 0000000..b81f4e8
--- /dev/null
+++ b/Code/waremon_data.py
@@ -0,0 +1,170 @@
+TRAINER_DATA = {
+ 'blond': {
+ 'dialog': { 'default': ['Salut!' , ' Enfin une nouvelle tête!' , ' Ca te dit un combat?'],
+ 'vaincu': ['Tu es plus fort que je le pensais!', 'Bien joué ']},
+ 'directions': ['down'],
+ 'look_around': True,
+ 'vaincu': False,
+ },
+ 'Boss': {
+ 'dialog': {'default': ['Je t attendais! ', ' Battons nous!'],
+ 'vaincu': ['ARGH!', 'Je te retrouv....']},
+ 'directions': ['down'],
+ 'look_around': True,
+ 'vaincu': False,
+ },
+ 'Daronne': {
+ 'dialog':{'default': ['Bonjour, tu veux etre mon ami ?', 'Pardon... Je voulais dire ennemie!'],
+ 'vaincu': ['Bon courage pour la suite!']},
+ 'directions': ['down'],
+ 'look_around': True,
+ 'vaincu': False,
+ },
+ 'Dresseur': {
+ 'dialog': {'default': ['J adore les nouveaux defis!', 'COMBATTONS!!!'],
+ 'vaincu': ['Bien joué...', 'Va voir le boss, tu vas souffrir!']},
+ 'directions': ['down'],
+ 'look_around': True,
+ 'vaincu': False,
+ },
+ 'fire_boss': {
+ 'dialog': {'deafult': ['J adore jouer avec le feu!', 'JOUONS!!'],
+ 'vaincu': ['Bonne chance...']},
+ 'directions': ['down'],
+ 'look_around': True,
+ 'vaincu': False,
+ },
+ 'grass_boss': {
+ 'dialog': {'default': ['Tu oses fouler ma terre ?!', 'Montre moi ce que tu vaut !'],
+ 'vaincu': ['#@*%&']},
+ 'directions': ['down'],
+ 'look_around': True,
+ 'vaincu': False,
+ },
+ 'hat_girl': {
+ 'dialog': {'default':['Salut toi!','J ai un petit jeu...'],
+ 'vaincu':['On peut plus jouer entres amis...']},
+ 'directions': ['down'],
+ 'look_around': True,
+ 'vaincu': False,
+ },
+ 'purple_girl': {
+ 'dialog': {'default': ['Les tenebres vont s abattre sur toi!!'],
+ 'vaincu': ['Les tenebres sont immortels....']},
+ 'directions': ['down'],
+ 'look_around': True,
+ 'vaincu': False,
+ },
+ 'straw': {
+ 'dialog': {'default': ['Salut toi!','Je m ennuis...', 'Ca te dit un combat?'],
+ 'vaincu': ['Bien joué', 'A bientot.']},
+ 'directions': ['down'],
+ 'look_around': True,
+ 'vaincu': False,
+ },
+ 'water_boss': {
+ 'dialog': {'default': ['Je vais te massacrer!!'],
+ 'vaincu': ['ARGH..','Je reviendr....']},
+ 'directions': ['down'],
+ 'look_around': True,
+ 'vaincu': False,
+ },
+ 'young_girl': {
+ 'dialog': {'default': ['Un petit combat ca te dit?'],
+ 'vaincu': ['Tu as triché!', 'Je te battrai!!']},
+ 'directions': ['down'],
+ 'look_around': True,
+ 'vaincu': False,
+ },
+ 'young_guy': {
+ 'dialog': {'default': ['Hey!', 'Tu as deja gouté a la defaite?', 'Non? Tu vas voir!!'],
+ 'vaincu': ['Très mauvais goût la defaite...']},
+ 'directions': ['down'],
+ 'look_around': True,
+ 'vaincu': False,
+ }
+
+}
+
+WAREMON_DATA = {
+ 'CryptoLocker' : {
+ 'statistiques': {'element': 'Ransomware', 'max_hp': '150', 'attaque': '20', 'defense' : '150', 'vitesse': '20' },
+ 'capacités' : {},
+ },
+ 'ExPtr': {
+ 'statistiques': {'element': 'Ransomware', 'max_hp': '70', 'attaque': '100', 'defense' : '50', 'vitesse': '70' },
+ 'capacités' : {},
+ },
+ 'GandCrab': {
+ 'statistiques': {'element': 'Ransomware', 'max_hp': '70', 'attaque': '60', 'defense' : '70', 'vitesse': '100' },
+ 'capacités' : {},
+ },
+ 'Locky': {
+ 'statistiques': {'element': 'Ransomware', 'max_hp': '150', 'attaque': '40', 'defense' : '70', 'vitesse': '30' },
+ 'capacités' : {},
+ },
+ 'Pinchy': {
+ 'statistiques': {'element': 'Ransomware', 'max_hp': '100', 'attaque': '40', 'defense' : '70', 'vitesse': '40' },
+ 'capacités' : {},
+ },
+
+ 'DarkHotel' : {
+ 'statistiques': {'element': 'Spyware', 'max_hp': '50', 'attaque': '150', 'defense' : '70', 'vitesse': '100' },
+ 'capacités' : {},
+ },
+ 'FinFisher': {
+ 'statistiques': {'element': 'Spyware', 'max_hp': '150', 'attaque': '100', 'defense' : '40', 'vitesse': '50' },
+ 'capacités' : {},
+ },
+ 'Havex': {
+ 'statistiques': {'element': 'Spyware', 'max_hp': '150', 'attaque': '50', 'defense' : '150', 'vitesse': '20' },
+ 'capacités' : {},
+ },
+ 'Pegasus': {
+ 'statistiques': {'element': 'Spyware', 'max_hp': '70', 'attaque': '70', 'defense' : '50', 'vitesse': '150' },
+ 'capacités' : {},
+ },
+ 'Regin': {
+ 'statistiques': {'element': 'Spyware', 'max_hp': '50', 'attaque': '70', 'defense' : '150', 'vitesse': '150' },
+ 'capacités' : {},
+ },
+
+ 'Dropper' : {
+ 'statistiques': {'element': 'Trojan', 'max_hp': '50', 'attaque': '150', 'defense' : '70', 'vitesse': '50' },
+ 'capacités' : {},
+ },
+ 'PC-Cyborg': {
+ 'statistiques': {'element': 'Trojan', 'max_hp': '150', 'attaque': '70', 'defense' : '70', 'vitesse': '70' },
+ 'capacités' : {},
+ },
+ 'SharkBot': {
+ 'statistiques': {'element': 'Trojan', 'max_hp': '100', 'attaque': '150', 'defense' : '70', 'vitesse': '50' },
+ 'capacités' : {},
+ },
+ 'Stuxnet': {
+ 'statistiques': {'element': 'Trojan', 'max_hp': '150', 'attaque': '40', 'defense' : '150', 'vitesse': '20' },
+ 'capacités' : {},
+ },
+ 'Zeus': {
+ 'statistiques': {'element': 'Trojan', 'max_hp': '100', 'attaque': '100', 'defense' : '40', 'vitesse': '20' },
+ 'capacités' : {},
+ },
+}
+
+CAPACITES_DATA = {
+ 'brûlure_virale': {'cible': 'adversaire', 'quantité': 2, 'multiplicateur': 15, 'élément': 'Trojan', 'animation': 'flamme'},
+ 'onde_de_choc': {'cible': 'adversaire', 'quantité': 3, 'multiplicateur': 20, 'élément': 'Trojan', 'animation': 'éclair'},
+ 'barrage_de_paquets': {'cible': 'adversaire', 'quantité': 1, 'multiplicateur': 10, 'élément': 'Trojan', 'animation': 'onde'},
+ 'survoltage': {'cible': 'soi-même', 'quantité': 2, 'multiplicateur': 12, 'élément': 'Trojan', 'animation': 'étincelle'},
+ 'parasite_logique': {'cible': 'adversaire', 'quantité': 3, 'multiplicateur': 18, 'élément': 'Spyware', 'animation': 'ver_informatique'},
+ 'effacement_critique': {'cible': 'adversaire', 'quantité': 5, 'multiplicateur': 25, 'élément': 'Ransomware', 'animation': 'erreur_fatale'},
+ 'patch_défensif': {'cible': 'soi-même', 'quantité': 3, 'multiplicateur': 15, 'élément': 'Spyware', 'animation': 'barrière'},
+ 'injection_SQL': {'cible': 'adversaire', 'quantité': 4, 'multiplicateur': 22, 'élément': 'Spyware', 'animation': 'texte_codé'},
+ 'chiffrement': {'cible': 'soi-même', 'quantité': 2, 'multiplicateur': 20, 'élément': 'Ransomware', 'animation': 'bouclier'},
+ 'Rançon': {'cible': 'adversaire', 'quantité': 3, 'multiplicateur': 17, 'élément': 'Ransomware', 'animation': 'billet'},
+ 'zero_day': {'cible': 'adversaire', 'quantité': 5, 'multiplicateur': 30, 'élément': 'Trojan', 'animation': 'explosion_codée'},
+ 'dévoration_CPU': {'cible': 'adversaire', 'quantité': 3, 'multiplicateur': 12, 'élément': 'Trojan', 'animation': 'spirale_énergie'},
+ 'Espionnage': {'cible': 'adversaire', 'quantité': 2, 'multiplicateur': 10, 'élément': 'Spyware', 'animation': 'Lunette espion'},
+ 'écran_bleu': {'cible': 'adversaire', 'quantité': 4, 'multiplicateur': 20, 'élément': 'Ransomware', 'animation': 'glitch'},
+ 'charge_électromagnétique': {'cible': 'adversaire', 'quantité': 3, 'multiplicateur': 15, 'élément': 'Trojan', 'animation': 'onde_électromagnétique'}
+}
\ No newline at end of file
diff --git a/data/maps/house.tmx b/data/maps/house.tmx
new file mode 100644
index 0000000..9d3cf56
--- /dev/null
+++ b/data/maps/house.tmx
@@ -0,0 +1,82 @@
+
+
diff --git a/data/maps/map3.tmx b/data/maps/map3.tmx
index b600874..8c992f8 100644
--- a/data/maps/map3.tmx
+++ b/data/maps/map3.tmx
@@ -1,1188 +1,1225 @@
-
-
+
+
diff --git a/data/tileset/indoor.tsx b/data/tileset/indoor.tsx
new file mode 100644
index 0000000..27613fe
--- /dev/null
+++ b/data/tileset/indoor.tsx
@@ -0,0 +1,4 @@
+
+
+
+