diff --git a/src/entities.py b/src/-entities.py similarity index 100% rename from src/entities.py rename to src/-entities.py diff --git a/src/dialogue.py b/src/dialogue.py index 5c04bd4..55ccf39 100644 --- a/src/dialogue.py +++ b/src/dialogue.py @@ -1,22 +1,27 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- - """ Gestion des dialogues entre le joueur et les NPC """ - import pygame as pg import sqlite3 as sql import numpy as np - class Dialogue(): DATABASE_LOCATION = "res/text/dialogues.db" IMAGE_LOCATION = "res/textures/talk_box_next.png" + + TEXT_POSITION = (30, 100) + def __init__(self, game, npc): self.game = game + self.current_npc = npc + + #Etat + self.is_writing = True + self.game.player.is_talking = True #Graphique self.talk_box_surf = pg.image.load(self.IMAGE_LOCATION).convert() @@ -24,6 +29,8 @@ def __init__(self, game, npc): self.talk_box_y = int(self.talk_box_surf.get_height()*0.75) self.talk_box_img = pg.transform.scale(self.talk_box_surf, (self.talk_box_x, self.talk_box_y)) self.talk_box_img.set_colorkey([255, 255, 255]) + self.tw_sound = pg.mixer.Sound( + "res/sounds/sound_effect/typewriter.wav") #BDD self.db_connexion = sql.connect(self.DATABASE_LOCATION) @@ -31,7 +38,6 @@ def __init__(self, game, npc): #Gestion de l'affichage partiel du texte self.lettre_cooldown = 5 - self.current_npc = npc self.current_text = "" # text actuel self.current_text_id = -1 # id du text actuel self.current_letter_id = -1 # lettre actuelle @@ -41,11 +47,6 @@ def __init__(self, game, npc): #Police self.font = pg.font.SysFont("comic sans ms", 16) - - self.tw_sound = pg.mixer.Sound( - "res/sounds/sound_effect/typewriter.wav") - self.is_writing = True - self.game.player.is_talking = True self.new_line() def close(self): @@ -67,7 +68,7 @@ def next_dialogue(self): if self.is_writing: self.is_writing = False self.current_letter_id = -1 - self.ecrire(self.current_text,30,100) + self.ecrire(self.current_text, self.TEXT_POSITION) else: self.new_line() @@ -90,16 +91,16 @@ def new_letter(self): """Affiche une nouvelle lettre du texte""" if self.current_letter_id < len(self.current_text) - 1: self.current_letter_id += 1 - self.ecrire(self.current_text[:self.current_letter_id+1], 30, 100) + self.ecrire(self.current_text[:self.current_letter_id+1], self.TEXT_POSITION) pg.mixer.Sound.play(self.tw_sound) else: self.current_letter_id = -1 self.is_writing = False - def ecrire(self, texte, x, y, color=(0, 0, 0)): + def ecrire(self, texte, pos, color=(0, 0, 0)): """Affiche le texte sur le cadre de dialogue""" text_affiche = self.font.render(texte, False, color) - self.talk_box_img.blit(text_affiche, (x, y)) + self.talk_box_img.blit(text_affiche, pos) def show_talk_box(self): """Affichage graphique de la boîte""" diff --git a/src/game.py b/src/game.py index 222a550..5bef939 100644 --- a/src/game.py +++ b/src/game.py @@ -19,26 +19,25 @@ def __init__(self): self.tick_count = 0 + #Objets associés self.player = player.Player(0, 0, self) self.map_manager = maps.MapManager(self.screen, self) self.dialogue = None def tick(self): + """Fonction principale de calcul du tick""" inputs.handle_pressed_key(self) - self.map_manager.update() + self.map_manager.tick() self.map_manager.draw() - self.player.update_player() if self.dialogue != None: self.dialogue.update() def run(self): - + """Boucle principale""" clock = pg.time.Clock() - running = True while running: - self.tick() pg.display.flip() # update l'ecran @@ -47,6 +46,9 @@ def run(self): running = False elif event.type == pg.KEYDOWN: inputs.handle_key_down_event(self, event) + self.tick_count += 1 + if self.tick_count % 60 == 0: + print("Running...", self.tick_count/60, end="\r") clock.tick(60) # 60 fps psk ça va trop vite pg.quit() diff --git a/src/inputs.py b/src/inputs.py index 2490957..cb65b74 100644 --- a/src/inputs.py +++ b/src/inputs.py @@ -2,11 +2,13 @@ import pygame as pg def handle_pressed_key(game): + """Transmet toutes les touches préssées""" pressed = pg.key.get_pressed() #Gestion des touches du clavier # On envoie le statut des 4 touches de déplacement pour être traité game.player.move([pressed[pg.K_UP], pressed[pg.K_RIGHT], pressed[pg.K_DOWN], pressed[pg.K_LEFT]], pressed[pg.K_RCTRL] or pressed[pg.K_LCTRL]) def handle_key_down_event(game, event): + """Transmet l'évènement d'une toucher qui vient d'être pressée""" if event.key == pg.K_SPACE: # si Espace est pressée if game.dialogue == None: game.map_manager.npc_manager.check_talk() diff --git a/src/maps.py b/src/maps.py index a5d8f27..3ce5aad 100644 --- a/src/maps.py +++ b/src/maps.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- + import pygame as pg import pytmx, pyscroll from dataclasses import dataclass @@ -31,11 +32,23 @@ class MapManager : # aka le Patron ou bien Le Contre-Maître def __init__ (self,screen,game): self.game = game self.screen = screen - self.maps = dict() # les dictionnaires c'est bien, surtout pour y ranger des cates + + #Etat self.current_map = "carte" # La map à charger par défault ( mais sert aussi d'indicateur sur la map actuellement utilisée) self.current_music = "titleVer2" # resp musique + + self.maps = dict() # les dictionnaires c'est bien, surtout pour y ranger des cates self.music_manager() # lancement de la musique - # référencement des différentes cartes (voir fonction d'après) + + self.register_all_maps() + + #Objets associés + self.npc_manager = npc.NpcManager(self) + + self.teleport_player("spawn_1") # Tp le j au spawn de base ( soit ici celui de carte.tmx) + + def register_all_maps(self): + # référencement des différentes cartes (voir fonction d'après) self.register_map("niv_1", "spring", portals =[ Portal (from_world = "niv_1", origin_point = "to_main", to_world = "carte", next_point = "spawn_lycée"), @@ -80,11 +93,6 @@ def __init__ (self,screen,game): Portal (from_world = "i109", origin_point = "to_niv1", to_world = "niv_1", next_point = "exit_i109") ]) - self.teleport_player("spawn_1") # Tp le j au spawn de base ( soit ici celui de carte.tmx) - - self.npc_manager = npc.NpcManager(self) - - def check_collision(self): 'condition de colision' # aux portals @@ -100,19 +108,14 @@ def check_collision(self): self.npc_manager = npc.NpcManager(self) self.teleport_player(copy_portal.next_point) # on téléporte le j sur le spawn d'arriver self.music_manager() # le Dj fait son taf ( TODO : peut être metttre un décompte pour changer de musique moins brusquement) - # aux murs - for sprite in self.get_group().sprites(): - if sprite.feet.collidelist(self.get_walls()) > -1: - sprite.move_back() def teleport_player(self, name): 'tp le joueur sur les coordonées de l objet name' point = self.get_object(name) self.game.player.position[0] = point.x # réaffectation des coordonées self.game.player.position[1] = point.y - self.game.player.save_location() # pour éviter les bugs de loop de tp - def register_map (self, name_map , name_music, portals = [] ): + def register_map(self, name_map , name_music, portals = [] ): 'enregistre une carte sur le ditionnaire self.maps de la classe MapManager' # chargement normal des elts d'une carte sur Tiled @@ -165,7 +168,7 @@ def draw(self): self.get_group().draw(self.screen) self.get_group().center(self.game.player.rect.center) - def update(self): + def tick(self): 'appelée, elle met à jour les elts suivants' self.get_group().update() self.check_collision() diff --git a/src/npc.py b/src/npc.py index 4ee07fb..8a5e784 100644 --- a/src/npc.py +++ b/src/npc.py @@ -13,6 +13,8 @@ class NpcManager(): def __init__(self, map): self.npc_group = pg.sprite.Group() self.map = map + + #On charge les Npc de la map for npc in NPC_LIST: if npc["map"] == map.current_map: new_npc = Npc(map, npc["id"], npc["coords"]) @@ -26,12 +28,15 @@ def check_talk(self): class Npc(pg.sprite.Sprite): + TEXTURE_FILE_LOCATION = 'res/textures/player.png' + def __init__(self, map, id, coords): super().__init__() self.map = map self.id = id - self.sprite_sheet = pg.image.load('res/textures/player.png') - #self.dialogue = self.game.dialogue + + #Graphique + self.sprite_sheet = pg.image.load(self.TEXTURE_FILE_LOCATION) self.image = pg.Surface([32, 32]) # creation d'une image self.image.set_colorkey([0, 0, 0]) # transparence self.rect = self.image.get_rect() # rectangle autour du joueur diff --git a/src/player.py b/src/player.py index 187a082..9eddef3 100644 --- a/src/player.py +++ b/src/player.py @@ -7,60 +7,107 @@ class Player(pg.sprite.Sprite): + TEXTURE_FILE_LOCATION = 'res/textures/player.png' + SPEED_NORMALISATION = 1/(2**0.5) BASE_WALK_SPEED = 1.5 #Vitesse du joueur sans multiplicateur (en m/frame) SPRINT_WALK_SPEED_MULTIPLIER = 1.75 #Multiplicateur de vitesse en cas de sprint WALK_ANIMATION_COOLDOWN = 8 #Cooldown entre deux changements d'animations (en frames) SPRINT_ANIMATION_COOLDOWN = 3 #Cooldown entre deux changements d'animations (en frames) + ANIMATION_DICT = { + "1,1" : "down-right", + "1,0" : "right", + "0,1" : "down", + "1,-1" : "up-right", + "0,-1" : "up", + "-1,1" : "down-left", + "-1,0" : "left", + "-1,-1" : "up-left"} + def __init__(self, x, y, game): super().__init__() self.game = game + + #Etat self.is_animated = False self.is_sprinting = False self.is_talking = False - self.sprite_sheet = pg.image.load('res/textures/player.png') + + self.position = [x, y] + + #Graphique + self.sprite_sheet = pg.image.load(self.TEXTURE_FILE_LOCATION) self.image = self.get_image(0, 0) # en bas par défaut self.image.set_colorkey([0, 0, 0]) # transparence self.rect = self.image.get_rect() # rectangle autour du joueur - self.position = [x, y] self.feet = pg.Rect(0, 0, self.rect.width * 0.5, 12) - self.old_position = self.position.copy() - self.images = { - 'down': [self.get_image(0, 0), self.get_image(32, 0), self.get_image(64, 0)], - 'left': [self.get_image(0, 32), self.get_image(32, 32), self.get_image(64, 32)], - 'right': [self.get_image(0, 64), self.get_image(32, 64), self.get_image(64, 64)], - 'up': [self.get_image(0, 96), self.get_image(32, 96), self.get_image(64, 96)] - } + self.current_sprite = 0 - def change_animation(self, sens): # change l'image en fonction du sens 'sens' - self.image = self.images[sens][int(self.current_sprite)] + self.IMAGES = { + 'down': [self.get_image(0, 0), self.get_image(32, 0), self.get_image(64, 0)], + 'down-left': [self.get_image(0, 0), self.get_image(32, 0), self.get_image(64, 0)], + 'down-right': [self.get_image(0, 0), self.get_image(32, 0), self.get_image(64, 0)], + 'left': [self.get_image(0, 32), self.get_image(32, 32), self.get_image(64, 32)], + 'right': [self.get_image(0, 64), self.get_image(32, 64), self.get_image(64, 64)], + 'up': [self.get_image(0, 96), self.get_image(32, 96), self.get_image(64, 96)], + 'up-left': [self.get_image(0, 96), self.get_image(32, 96), self.get_image(64, 96)], + 'up-right': [self.get_image(0, 96), self.get_image(32, 96), self.get_image(64, 96)] + } + + + def change_animation(self, direction): # change l'image en fonction du sens 'sens' + animation = self.ANIMATION_DICT[str(direction[0])+","+str(direction[1])] + self.image = self.IMAGES[animation][int(self.current_sprite)] self.image.set_colorkey([0, 0, 0]) # transparence + def is_colliding(self): + return True if self.feet.collidelist(self.game.map_manager.get_walls()) > -1 else False + def move(self, list_directions, sprinting): - if not self.is_talking: - number_directions = list_directions.count(True) - speed_multiplier = self.SPRINT_WALK_SPEED_MULTIPLIER if sprinting else 1 - self.is_sprinting = True if sprinting else False - speed_normalisation = self.SPEED_NORMALISATION if number_directions == 2 else 1 - self.is_animated = False if number_directions in [0,4] else True - if list_directions[0]: #Haut - self.position[1] -= self.BASE_WALK_SPEED*speed_multiplier*speed_normalisation - self.change_animation('up') - if list_directions[1]: #Droite - self.position[0] += self.BASE_WALK_SPEED*speed_multiplier*speed_normalisation - self.change_animation('right') - if list_directions[2]: #Bas - self.position[1] += self.BASE_WALK_SPEED*speed_multiplier*speed_normalisation - self.change_animation('down') - if list_directions[3]: #Gauche - self.position[0] -= self.BASE_WALK_SPEED*speed_multiplier*speed_normalisation - self.change_animation('left') + if list_directions.count(True) > 0: + if not self.is_talking: + speed_multiplier = self.SPRINT_WALK_SPEED_MULTIPLIER if sprinting else 1 + self.is_sprinting = True if sprinting else False + deplacement = [0, 0] + if list_directions[0]: #Haut + deplacement[1] -= 1 + if list_directions[1]: #Droite + deplacement[0] += 1 + if list_directions[2]: #Bas + deplacement[1] += 1 + if list_directions[3]: #Gauche + deplacement[0] -= 1 + + if deplacement[0] != 0 or deplacement[1] != 0: + + if deplacement[0] != 0 and deplacement[1] != 0: + speed_normalisation = self.SPEED_NORMALISATION + else: + speed_normalisation = 1 + + for coord_id in [0, 1]: + self.position[coord_id] += deplacement[coord_id]*self.BASE_WALK_SPEED*speed_multiplier*speed_normalisation + self.rect.topleft = self.position + self.feet.midbottom = self.rect.midbottom + + # Si il y a collision, on annule le dernier déplacement + if self.is_colliding(): + self.position[coord_id] -= deplacement[coord_id]*self.BASE_WALK_SPEED*speed_multiplier*speed_normalisation + + self.rect.topleft = self.position + self.feet.midbottom = self.rect.midbottom + else: + self.is_animated = True + self.change_animation(deplacement) + else: + self.is_animated = False def update(self): # mettre à jour la position self.rect.topleft = self.position self.feet.midbottom = self.rect.midbottom + animation_cooldown = self.SPRINT_ANIMATION_COOLDOWN if self.is_sprinting else self.WALK_ANIMATION_COOLDOWN if self.is_animated == True: self.current_sprite = (int(self.game.tick_count/animation_cooldown) % 3) @@ -70,14 +117,3 @@ def get_image(self, x, y): image = pg.Surface([32, 32]) image.blit(self.sprite_sheet, (0, 0), (x, y, 32, 32)) return image - - def save_location(self): - self.old_position = self.position.copy() - - def update_player(self): # est appelée à chaques tick - self.save_location() - - def move_back(self): - self.position = self.old_position - self.rect.topleft = self.position - self.feet.midbottom = self.rect.midbottom