Merge pull request 'Amélioration de l'engine et ajout d'éléments de gameplay' (#20) from debut_jeu into main

Reviewed-on: Really-Fun-Games/NSI-RPG#20
This commit is contained in:
Yannis 2024-01-03 19:20:44 +00:00 committed by Gitea
commit e082164896
No known key found for this signature in database
24 changed files with 3206 additions and 169 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 768 B

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 774 B

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 804 B

After

Width:  |  Height:  |  Size: 408 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 766 B

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 771 B

After

Width:  |  Height:  |  Size: 405 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 766 B

After

Width:  |  Height:  |  Size: 405 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View file

@ -43,6 +43,12 @@
"name":"water",
"probability":1,
"tile":4
},
{
"color":"#ff00d8",
"name":"path",
"probability":1,
"tile":433
}],
"name":"forest ground",
"tile":1,
@ -134,7 +140,7 @@
},
{
"tileid":92,
"wangid":[0, 0, 0, 5, 0, 0, 0, 5]
"wangid":[0, 4, 0, 5, 0, 4, 0, 5]
},
{
"tileid":96,
@ -415,6 +421,66 @@
{
"tileid":353,
"wangid":[0, 3, 0, 3, 0, 3, 0, 2]
},
{
"tileid":408,
"wangid":[0, 1, 0, 6, 0, 1, 0, 1]
},
{
"tileid":409,
"wangid":[0, 1, 0, 6, 0, 6, 0, 1]
},
{
"tileid":410,
"wangid":[0, 1, 0, 1, 0, 6, 0, 1]
},
{
"tileid":417,
"wangid":[0, 1, 0, 6, 0, 1, 0, 6]
},
{
"tileid":432,
"wangid":[0, 6, 0, 6, 0, 1, 0, 1]
},
{
"tileid":433,
"wangid":[0, 6, 0, 6, 0, 6, 0, 6]
},
{
"tileid":434,
"wangid":[0, 1, 0, 1, 0, 6, 0, 6]
},
{
"tileid":437,
"wangid":[0, 6, 0, 1, 0, 6, 0, 6]
},
{
"tileid":438,
"wangid":[0, 6, 0, 6, 0, 1, 0, 6]
},
{
"tileid":441,
"wangid":[0, 6, 0, 1, 0, 6, 0, 1]
},
{
"tileid":456,
"wangid":[0, 6, 0, 1, 0, 1, 0, 1]
},
{
"tileid":457,
"wangid":[0, 6, 0, 1, 0, 1, 0, 6]
},
{
"tileid":458,
"wangid":[0, 1, 0, 1, 0, 1, 0, 6]
},
{
"tileid":461,
"wangid":[0, 1, 0, 6, 0, 6, 0, 6]
},
{
"tileid":462,
"wangid":[0, 6, 0, 6, 0, 6, 0, 1]
}]
},
{

File diff suppressed because it is too large Load diff

69
src/custom_AI.py Normal file
View file

@ -0,0 +1,69 @@
import math
import random
from src.engine.entity import Entity
from src.engine.entity_manager import EntityManager
from src.engine.map_manager import MapManager
from src.engine.mobs_AI import MobAI
class WolfAI(MobAI):
def __init__(self, entity: 'Entity', entity_manager: 'EntityManager', map_manager: 'MapManager'):
super().__init__(entity, entity_manager, map_manager)
self.ATTACK_DISTANCE = 160
self.timer = 0
self.walk_x = 0
self.walk_y = 0
self.comportment = 0 # 0 : waiting, 1: walking
def update(self, delta: float):
"""Fonction executée à chaque tick pour chaque loup et qui gère l'IA."""
# On récupère l'entité joueur
player: Entity = self.entity_manager.get_by_name(self.entity_manager.player_entity_name)
# On calcule la distance en x et en y entre le loup et le joueur
x_distance = (player.x - self.entity.x)
y_distance = (player.y - self.entity.y)
# On calcule la distance
player_distance = math.sqrt(x_distance ** 2 + y_distance ** 2)
# On vérifie que le loup peut voir le joueur
if player_distance <= self.ATTACK_DISTANCE:
# On rétablit la vitesse du loup à 1
self.entity.max_speed = 1.
# Si le loup touche le joueur, il lui inflige des dégats
if player.get_collisions_with_entity(self.entity):
player.take_damages(1)
# Si le loup n'est pas déja sur le joueur, on le fait s'en raprocher
if player_distance > self.entity.max_speed:
self.entity.move(x_distance / player_distance*self.entity.max_speed,
y_distance / player_distance*self.entity.max_speed, self.map_manager)
else:
# Comportement d'attente
# On diminue la vitesse
self.entity.max_speed = 0.5
self.timer -= delta
# Si le timer est fini et que le loup était en train d'attendre, il commence à marcher
if self.timer <= 0 and self.comportment == 0:
self.comportment = 1
self.timer = random.random() * 5.
# On choisit la direction
self.walk_x = (random.random()-0.5)*2
self.walk_y = (random.random()-0.5)*2
# Si le timer est fini et que le loup était de marcher, il commence à attendre
elif self.timer <= 0 and self.comportment == 1:
self.comportment = 0
self.timer = random.random() * 3
# On fait avancer le loup quand il le doit
if self.comportment == 1:
self.entity.move(self.walk_x, self.walk_y, self.map_manager)

View file

@ -7,6 +7,9 @@ class Camera:
self.y = 0
self.zoom = 1.
# Décalage lors du mouvement du joueur
self.player_moving_offset = 100
# Variables utilisées pour le scrolling
self.target_x = self.x
self.target_y = self.y
@ -21,8 +24,10 @@ class Camera:
# Si on suit une entité, on met à jour les coordonnées de suivi
if self.followed_entity is not None:
self.target_x = self.followed_entity.x
self.target_y = self.followed_entity.y
self.target_x = (self.followed_entity.x + self.followed_entity.mouvements[0] *
self.player_moving_offset / self.zoom)
self.target_y = (self.followed_entity.y + self.followed_entity.mouvements[1] *
self.player_moving_offset / self.zoom)
self.x += (self.target_x - self.x) / self.smoothness
self.y += (self.target_y - self.y) / self.smoothness

View file

@ -29,7 +29,7 @@ class Engine:
self.event_handler = EventHandler(self)
self.map_manager = MapManager()
self.camera = Camera()
self.entity_manager = EntityManager()
self.entity_manager = EntityManager(self.map_manager)
self.boss_fight_manager = BossFightManager(self)
def loop(self):

View file

@ -1,4 +1,7 @@
import math
from src.engine.map_manager import MapManager
from src.engine.mobs_AI import MobAI
class Entity:
@ -8,6 +11,16 @@ class Entity:
self.x = 8
self.y = 8
self.direction = 0 # 0 : tourné vers la droite (ou sens par défaut), 1 : tourné vers la gauche (ou retourné)
# Variables utilisées pour détecter les mouvements
self.last_x = 0
self.last_y = 0
self.mouvements = [0., 0.]
self.max_speed = 1.
self.life_points = -1
self.max_life_points = -1
@ -19,16 +32,26 @@ class Entity:
# Time utilisé pour les IA
self.time = 0
self.brain: MobAI | None = None
self.name = name
self.animation_name = None
self.shadow = None
def set_default_life(self, life: int):
"""Définit le nombre de PV de l'entité. Mettre -1 pour rendre l'entité immortelle."""
self.life_points = life
self.max_life_points = life
def set_ai(self, ai: MobAI, engine: 'Engine'):
"""Enregistre une classe permettant de gérer l'IA du mob."""
# La ligne suivante crée une instance de la classe d'IA. Cette ligne peut causer des warnings sur certains IDE
# mais elle est bien valide
self.brain = ai(self, engine.entity_manager, engine.map_manager)
def update(self, delta: float):
"""Met à jour l'entité."""
self.time += delta
@ -38,6 +61,14 @@ class Entity:
if self.damage_cooldown < 0:
self.damage_cooldown = 0
# Si les coordonnées ont changé, l'entité a bougé
self.mouvements[0] = (self.x - self.last_x) / self.max_speed
self.mouvements[1] = (self.y - self.last_y) / self.max_speed
self.last_x = self.x
self.last_y = self.y
def take_damages(self, damages: int):
"""Inflige {damages} dégâts à l'entité."""
@ -51,15 +82,22 @@ class Entity:
if self.life_points < 0:
self.life_points = 0
def get_collisions_with_entity(self, other: 'Entity'):
"""Retourne True si l'entité courante est en collision avec l'entité donnée."""
return (self.x+self.collision_rect[0] <= other.x+other.collision_rect[2] and
self.x+self.collision_rect[2] >= other.x+other.collision_rect[0] and
self.y+self.collision_rect[3] >= other.y+other.collision_rect[1] and
self.y+self.collision_rect[1] <= other.y+other.collision_rect[3])
def get_collisions(self, x: float, y: float, map_manager: MapManager):
"""Calcule les collisions."""
# On calcule les coordonnées des points en haut à gauche et en bas à droite
top_left_corner_tile = (int((x + self.collision_rect[0]) / 16),
int((y + self.collision_rect[1]) / 16))
top_left_corner_tile = (math.floor((x + self.collision_rect[0]) / 16),
math.floor((y + self.collision_rect[1]) / 16))
bottom_right_corner_tile = (int((x + self.collision_rect[2]-1) / 16),
int((y + self.collision_rect[3]-1) / 16))
bottom_right_corner_tile = (math.floor((x + self.collision_rect[2]-1) / 16),
math.floor((y + self.collision_rect[3]-1) / 16))
collision = False
@ -79,6 +117,19 @@ class Entity:
def move(self, x: float, y: float, map_manager: MapManager):
"""Fait bouger l'entité en tenant compte des collisions."""
# On vérifie le sens du mouvement pour changer self.direction
if x > 0:
self.direction = 0
elif x < 0:
self.direction = 1
# On ne met pas de else car si x = 0, on ne change pas de direction
# On normalise la vitesse
initial_speed = math.sqrt(x**2+y**2)
x = x/initial_speed*self.max_speed
y = y/initial_speed*self.max_speed
# On simule le mouvement. Si on ne rencontre pas de collision, on applique le mouvement
if not self.get_collisions(self.x + x, self.y, map_manager):
self.x += x

View file

@ -1,17 +1,29 @@
from src.engine.entity import Entity
from src.engine.map_manager import MapManager
class EntityManager:
"""Classe chargée de gérer les entités."""
def __init__(self):
def __init__(self, map_manager: MapManager):
self.entities: dict[str:Entity] = {}
self.player_entity_name = ""
self.map_manager = map_manager
def register_entity(self, name: str):
def register_entity(self, name: str) -> Entity:
"""Crée une entité et l'enregistre dans un dictionnaire."""
entity = Entity(name)
self.entities[name] = entity
return entity
def set_player_entity(self, name: str):
"""Définit l'entité donnée comme le joueur. Elle peut donc être controlée."""
self.player_entity_name = name
def move_player_controls(self, x: float, y: float):
"""Bouge le joueur. X et y doivent être compris entre 0 et 1"""
player: Entity = self.get_by_name(self.player_entity_name)
player.move(x, y, self.map_manager)
def update(self, delta: float):
"""Met à jour toutes les entités enregistrées."""
for entity_name in list(self.entities.keys()):
@ -20,10 +32,20 @@ class EntityManager:
if entity.life_points == 0:
self.entities.pop(entity_name)
def get_all_entities(self):
if entity.brain is not None:
entity.brain.update(delta)
if self.player_entity_name:
player: Entity = self.get_by_name(self.player_entity_name)
if player.mouvements[0] != 0. or player.mouvements[1] != 0.:
player.link_animation("player_walking")
else:
player.link_animation("player_none")
def get_all_entities(self) -> list[Entity]:
"""Donne la liste de toutes les entités enregistrées."""
return list(self.entities.values())
def get_by_name(self, name: str):
def get_by_name(self, name: str) -> Entity:
"""Donne l'entité avec le nom donné."""
return self.entities[name]

View file

@ -1,3 +1,5 @@
import math
from pygame import event
from pygame.locals import *
@ -22,24 +24,29 @@ class EventHandler:
elif e.type == KEYUP:
self.key_pressed.remove(e.key)
player = self.engine.entity_manager.get_by_name("player")
player.link_animation("player_none")
if K_RIGHT in self.key_pressed:
player.move(2, 0, self.engine.map_manager)
player.link_animation("player_walking")
if K_LEFT in self.key_pressed:
player.move(-2, 0, self.engine.map_manager)
player.link_animation("player_walking")
if K_UP in self.key_pressed:
player.move(0, -2, self.engine.map_manager)
player.link_animation("player_walking")
if K_DOWN in self.key_pressed:
player.move(0, 2, self.engine.map_manager)
player.link_animation("player_walking")
if self.engine.entity_manager.player_entity_name:
if K_RIGHT in self.key_pressed:
self.engine.entity_manager.move_player_controls(1, 0)
if K_LEFT in self.key_pressed:
self.engine.entity_manager.move_player_controls(-1, 0)
if K_UP in self.key_pressed:
self.engine.entity_manager.move_player_controls(0, -1)
if K_DOWN in self.key_pressed:
self.engine.entity_manager.move_player_controls(0, 1)
if self.engine.DEBUG_MODE:
if K_l in self.key_pressed:
self.engine.entity_manager.get_by_name("player").take_damages(1)
if K_p in self.key_pressed:
self.engine.renderer.emit_particles(math.floor(self.engine.entity_manager.get_by_name("player").x),
math.floor(self.engine.entity_manager.get_by_name("player").y),
16, 16, 16, 1, 8, 0, 1, 0.2, 1., (0, 200, 200))
if K_o in self.key_pressed:
print(f"Player pos: X = {self.engine.entity_manager.get_by_name('player').x} "
f"Y = {self.engine.entity_manager.get_by_name('player').y}")
if K_x in self.key_pressed:
self.engine.camera.target_zoom *= 1.01
if K_c in self.key_pressed:
self.engine.camera.target_zoom *= 0.99
if K_l in self.key_pressed:
player.take_damages(1)

View file

@ -28,18 +28,20 @@ class MapManager:
# On calcule les coordonnées du chunk
coordinates = (x//self.chunk_width, y//self.chunk_height)
# On transforme les coordonnées globales en coordonnées dans le chunk
x %= 16
y %= 16
# On vérifie que le chunk existe
if coordinates in layer:
chunk = layer[coordinates]
if coordinates not in layer:
return 0
# On transforme les coordonnées globales en coordonnées dans le chunk,
# On calcule l'index et on renvoie la tile
return chunk[x % 16 + y % 16 * self.chunk_width]
chunk = layer[coordinates]
# Si on ne trouve pas le chunk, on renvoit "vide"
return 0
# On vérifie que la tile demandée existe sinon on répond "vide"
if x >= self.chunk_width or x < 0 or y >= self.chunk_height or y < 0:
return 0
# On calcule l'index et on renvoie la tile
return chunk[x+y*self.chunk_width]
def get_tile_at_quick(self, x: int, y: int, layer_id: int):
"""Version optimisée de get_tile_at()."""
chunk = self.map_layers[layer_id].get((x//self.chunk_width, y//self.chunk_height))
if chunk is not None:
return chunk[x % 16 + y % 16 * self.chunk_width]
return 0

12
src/engine/mobs_AI.py Normal file
View file

@ -0,0 +1,12 @@
import math
class MobAI:
def __init__(self, entity_: 'entity.Entity', entity_manager: 'EntityManager', map_manager: 'MapManager'):
self.entity = entity_
self.entity_manager = entity_manager
self.map_manager = map_manager
def update(self):
pass

View file

@ -1,6 +1,7 @@
import math
import random
from pygame import display, image, surface, transform, draw
from pygame import display, image, surface, transform, draw, font
from pygame.locals import RESIZABLE, SRCALPHA, FULLSCREEN
import src.engine.engine as engine
@ -13,7 +14,7 @@ class Renderer:
def __init__(self, core: 'engine.Engine'):
self.engine = core
self.window_type = FULLSCREEN
self.window_type = RESIZABLE
self.window_size = (display.Info().current_w, display.Info().current_h) if self.window_type == FULLSCREEN else (600, 600)
self.window = display.set_mode(self.window_size, self.window_type)
self.tiles = []
@ -28,9 +29,43 @@ class Renderer:
# Variables utilisées par le menu principal
self.main_menu_assets: dict[str: Anim] = {}
# Ombres d'entités
self.shadows = {}
# Particules affichées
self.particles = []
def emit_particles(self, x: int, y: int, w: int, h: int, count: int, min_size: int, max_size: int,
min_speed: float, max_speed: float, min_life_time: float, max_life_time: float,
color: tuple[int, int, int]):
"""Emmet des particules aux coordonnées données dans un rectangle de demi-largeur {w} et de demi-hauteur {h}."""
for _ in range(count):
# On choisit la taille de la particule
part_size = random.randint(min_size, max_size)
# On choisit sa vitesse en x et en y
part_speed_x = random.uniform(min_speed, max_speed)
# On inverse la vitesse de manière aléatoire
if random.randint(0, 1) == 1:
part_speed_x = - part_speed_x
part_speed_y = random.uniform(min_speed, max_speed)
if random.randint(0, 1) == 1:
part_speed_y = - part_speed_y
# On choisit sa position dans le rectangle
part_x = random.randint(x-w, x+w-part_size)
part_y = random.randint(y-h, y+h-part_size)
# On choisit la durée de vie
part_life_time = random.uniform(min_life_time, max_life_time)
# On ajoute la particule dans la liste des particules
# Le 0 correspond au temps de vie depuis la création de la particule
self.particles.append([part_x, part_y, part_size, part_speed_x, part_speed_y, 0., part_life_time, color])
def load_main_menu_assets(self, path: str):
"""Charge les assets du menu principal depuis le dossier donné."""
def load_tile_set(self, file_path: str, tile_size: int):
"""Charge le jeu de tuiles en utilisant le fichier donné et la taille donnée."""
@ -61,6 +96,7 @@ class Renderer:
self.render_layer(0, rendered_surface)
self.render_layer(1, rendered_surface)
self.render_entities(rendered_surface, gui_surface, delta)
self.render_particles(rendered_surface, delta)
self.render_layer(2, rendered_surface)
# Enfin, on redimensionne notre surface et on la colle sur la fenêtre principale
@ -76,9 +112,24 @@ class Renderer:
self.render_boss_fight_scene(delta)
self.render_boss_fight_gui()
# Conteur de FPS en mode DEBUG
if self.engine.DEBUG_MODE:
self.window.blit(font.SysFont("Arial", 20).render(f"FPS: {self.engine.clock.get_fps()}", True, (255, 0, 0)),
(0, 0))
player = self.engine.entity_manager.get_by_name('player')
self.window.blit(font.SysFont("Arial", 20).render(f"X: {player.x} Y:{player.y}",
True, (255, 0, 0)), (0, 30))
self.window.blit(font.SysFont("Arial", 20).render(f"Zoom: {self.engine.camera.zoom}",
True, (255, 0, 0)), (0, 60))
# Apres avoir tout rendu, on met à jour l'écran
display.update()
def register_shadow(self, file_path: str, name: str):
"""Enregistre une image d'ombre utilisée pour le rendu des entités."""
shadow = image.load(file_path).convert_alpha()
self.shadows[name] = shadow
def register_animation(self, animation: Anim, name: str):
"""Enregistre une animation."""
self.animations[name] = animation
@ -91,6 +142,22 @@ class Renderer:
"""Ajoute une animation pour le joueur lors d'un combat de boss."""
self.boss_fight_player_animations[name] = animation
def render_particles(self, rendered_surface: surface.Surface, delta: float):
"""Update et rend les particules."""
x_middle_offset = display.get_window_size()[0] / 2 / self.engine.camera.zoom
y_middle_offset = display.get_window_size()[1] / 2 / self.engine.camera.zoom
for part in self.particles.copy():
part_dest = (math.floor(part[0] - self.engine.camera.x + x_middle_offset),
math.floor(part[1] - self.engine.camera.y + y_middle_offset))
draw.rect(rendered_surface, part[7], part_dest + (part[2], part[2]))
part[5] += delta
part[0] += part[3]
part[1] += part[4]
if part[5] > part[6]:
self.particles.remove(part)
def render_boss_fight_scene(self, delta: float):
"""Rend les sprites du joueur et du boss lors d'un combat de boss."""
@ -118,7 +185,8 @@ class Renderer:
def render_boss_fight_gui(self):
"""Rend la barre d'action en bas de l'écran pendant le combat de boss."""
resized_container = transform.scale(self.boss_fight_GUI_container, (display.get_window_size()[0], self.boss_fight_GUI_container.get_height()/self.boss_fight_GUI_container.get_width()*display.get_window_size()[0]))
resized_container = transform.scale(self.boss_fight_GUI_container,
(display.get_window_size()[0], self.boss_fight_GUI_container.get_height()/self.boss_fight_GUI_container.get_width()*display.get_window_size()[0]))
self.window.blit(resized_container, (0, display.get_window_size()[1]-resized_container.get_height()))
def render_entities(self, rendered_surface: surface.Surface, gui_surface: surface.Surface, delta: float):
@ -139,10 +207,20 @@ class Renderer:
entity.y - self.engine.camera.y - y_middle_offset - frame.get_height() > 0):
continue
# On flip l'image horizontalement si l'entité est retournée
if entity.direction == 1:
frame = transform.flip(frame, True, False)
# On calcule les coordonnées de rendu de l'entité
entity_dest = (math.floor(entity.x - self.engine.camera.x + x_middle_offset - frame.get_width() / 2),
math.floor(entity.y - self.engine.camera.y + y_middle_offset - frame.get_height() / 2))
# On récupert l'ombre de l'entité
if entity.shadow is not None:
shadow_image = self.shadows[entity.shadow]
# On rend l'ombre
rendered_surface.blit(shadow_image, entity_dest)
# On affiche l'image
rendered_surface.blit(frame, entity_dest)
@ -203,12 +281,18 @@ class Renderer:
x_map_offset = math.floor((self.engine.camera.x - x_middle_offset) / self.tile_size)
y_map_offset = math.floor((self.engine.camera.y - y_middle_offset) / self.tile_size)
# On précalcule le décallage des tiles sur l'écran
tile_x_offset = - self.engine.camera.x + x_middle_offset
tile_y_offset = - self.engine.camera.y + y_middle_offset
# On itère pour chaque couche, toutes les tiles visibles par la caméra
for x in range(x_map_offset, x_map_offset + x_map_range):
# On précalcule les coordonnées en x
tile_render_x = math.floor(x * self.tile_size + tile_x_offset)
for y in range(y_map_offset, y_map_offset + y_map_range):
# On récupère l'id de la tile à la position donnée
tile_id = self.engine.map_manager.get_tile_at(x, y, layer_id)
tile_id = self.engine.map_manager.get_tile_at_quick(x, y, layer_id)
# Si l'id est 0, il s'agit de vide donc on saute le rendu
if tile_id == 0:
@ -216,5 +300,11 @@ class Renderer:
# Puis, on cherche à quelle image elle correspond et on la colle sur notre surface
rendered_surface.blit(self.tiles[tile_id - 1],
(math.floor(x * self.tile_size - self.engine.camera.x + x_middle_offset),
math.floor(y * self.tile_size - self.engine.camera.y + y_middle_offset)))
(tile_render_x,
math.floor(y * self.tile_size + tile_y_offset)))
if self.engine.DEBUG_MODE and layer_id == 1:
draw.rect(rendered_surface, (100, 100, 255),
(math.floor(x * self.tile_size - self.engine.camera.x + x_middle_offset),
math.floor(y * self.tile_size - self.engine.camera.y + y_middle_offset),
self.tile_size, self.tile_size), width=1)

View file

@ -1,5 +1,6 @@
import pygame.image
from src.custom_AI import WolfAI
from src.engine.animation import Anim
from src.engine.engine import Engine
from src.engine.enums import GameState
@ -14,8 +15,9 @@ class Game(Engine):
self.create_player_entity()
self.load_boss_fight_assets()
self.spawn_mobs()
self.DEBUG_MODE = True
self.DEBUG_MODE = False
self.game_state = GameState.NORMAL
@ -33,10 +35,34 @@ class Game(Engine):
player.link_animation("player_none")
player.collision_rect = [-6, -7, 6, 16]
player.set_default_life(10)
player.set_default_life(15)
player.max_speed = 1.1
self.entity_manager.set_player_entity("player")
player.shadow = "player_shadow"
self.renderer.register_shadow("assets/textures/entities/player/shadow.png", "player_shadow")
self.camera.follow_entity(player)
def spawn_mobs(self):
"""Fait apparaitre les mobs de la map."""
anim = Anim(0.5)
anim.load_animation_from_directory("assets/textures/entities/wolf/none")
self.renderer.register_animation(anim, "wolf_none")
mob = self.entity_manager.register_entity("wolf1")
mob.set_ai(WolfAI, self)
mob.link_animation("wolf_none")
mob.collision_rect = [-15, -7, 12, 7]
mob.set_default_life(5)
mob.max_speed = 1.
mob.x, mob.y = 160, 16
def load_boss_fight_assets(self):
"""Charge les animations de combat des combats de boss."""
player_none = Anim(1)