From a235f8f77e02a9e66e00dd99c2bde53bf7d2888e Mon Sep 17 00:00:00 2001 From: papush! Date: Mon, 9 Dec 2019 15:29:35 +0100 Subject: [PATCH] =?UTF-8?q?int=C3=A9gration=20de=20la=20recherche=20de=20c?= =?UTF-8?q?hemin=20super=20int=C3=A9lligente?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scenes/game_objects/common.py | 10 ++ scenes/game_objects/ghost.py | 58 +++++++++--- scenes/game_objects/level.py | 35 ++++++- scenes/game_objects/pacman.py | 28 ++++-- scenes/lvl0.py | 6 +- scenes/lvl0_fantome.py | 171 ---------------------------------- 6 files changed, 114 insertions(+), 194 deletions(-) delete mode 100644 scenes/lvl0_fantome.py diff --git a/scenes/game_objects/common.py b/scenes/game_objects/common.py index 2d34628..d331f1c 100644 --- a/scenes/game_objects/common.py +++ b/scenes/game_objects/common.py @@ -1 +1,11 @@ +from enum import Enum + + S = 20 + + +class Direction(Enum): + UP = 0 + DOWN = 1 + LEFT = 2 + RIGHT = 3 diff --git a/scenes/game_objects/ghost.py b/scenes/game_objects/ghost.py index ce93f55..6f923dc 100644 --- a/scenes/game_objects/ghost.py +++ b/scenes/game_objects/ghost.py @@ -1,24 +1,17 @@ -from enum import Enum from random import random, randint from pygame import Surface, draw, Rect, image from engine.entity import Entity +from engine.scene_manager import SceneManager from engine.resources import res from engine.components.collide_rect import CollideRect from engine.components.sprite import Sprite -from .common import S +from .common import S, Direction from .pacdot import PacDot -class Direction(Enum): - UP = 1 - DOWN = 2 - LEFT = 3 - RIGHT = 4 - - class Ghost(Entity): SPEED = 1 @@ -30,14 +23,14 @@ class Ghost(Entity): sprite.width, sprite.width), static=False, solid=False, - cb=self.on_col) + cb=self.cb) self.add(self.phys) self.script = Ghost.script self.x = x self.y = y - self.direction = Direction(randint(1, 4)) + self.direction = Direction(randint(0, 3)) - def on_col(self, c): + def cb(self, c): if not c.solid: return @@ -63,6 +56,30 @@ class Ghost(Entity): return def script(self): + # graph = SceneManager().scene.entities['level'].graph + + # cur_node = graph[self.y//S][self.x//S] + # # print(self.y//S, self.x//S) + # pacman = SceneManager().scene.entities['pacman'] + # x_dist = pacman.x - self.x + # y_dist = pacman.y - self.y + # s = 1 + # p = self.find_shortest_path(graph[pacman.y//S][pacman.x//S]) + # # print([x[1] for x in p]) + # cur_dir = p[0][1] + # if cur_dir == Direction.UP: + # self.phys.vx = 0 + # self.phys.vy = -1 + # elif cur_dir == Direction.DOWN: + # self.phys.vx = 0 + # self.phys.vy = 1 + # elif cur_dir == Direction.LEFT: + # self.phys.vx = -1 + # self.phys.vy = 0 + # else: + # self.phys.vx = 1 + # self.phys.vy = 0 + if self.direction == Direction.UP: self.phys.vy = -Ghost.SPEED self.phys.vx = 0 @@ -75,3 +92,20 @@ class Ghost(Entity): elif self.direction == Direction.RIGHT: self.phys.vx = Ghost.SPEED self.phys.vy = 0 + + def find_shortest_path(self, final_node): + graph = SceneManager().scene.entities['level'].graph + cur_node = graph[self.y//S][self.x//S] + children = cur_node.children + trace = [cur_node] + [x[0] for x in children] + paths = [[x] for x in children] + while 1: + cur_len = len(paths) + for path in paths[:cur_len]: + for child in path[-1][0].children: + if child[0] is not None and child[0] not in trace: + trace.append(child[0]) + paths.append(path + [child]) + if child[0] == final_node: + return path + paths = paths[cur_len:] diff --git a/scenes/game_objects/level.py b/scenes/game_objects/level.py index a2f0e0e..826cc04 100644 --- a/scenes/game_objects/level.py +++ b/scenes/game_objects/level.py @@ -8,10 +8,27 @@ from engine.servers.graphics import GraphicsServer from engine.components.collide_rect import CollideRect from engine.components.sprite import Sprite -from .common import S +from .common import S, Direction from .pacdot import PacDot, EnsmallmentDot +class Node(): + cpt = 0 + def __init__(self): + self.id = self.__class__.cpt + self.__class__.cpt += 1 + self.neighbors = [None for dir in Direction] + + @property + def children(self): + children = [] + for direction in Direction: + node = self.neighbors[direction.value] + if node is not None: + children.append((node, direction)) + return children + + class Level(Entity): def __init__(self, path): super().__init__('level') @@ -25,6 +42,7 @@ class Level(Entity): self.surf.fill((0, 0, 0)) wall = Surface((S, S)).convert() wall.fill((0, 0, 255)) + self.graph = [[None for x in range(w)] for y in range(h)] for x, y in product(range(w), range(h)): col = desc.get_at((x, y)) if col == (0, 0, 255): @@ -36,9 +54,24 @@ class Level(Entity): pc.y = y * S self.scene.add(pc) PacDot.tot += 1 + self.graph[y][x] = Node() + elif col == (0, 0, 0) or col == (255, 0, 0): + self.graph[y][x] = Node() elif col == (193, 193, 193): pc = EnsmallmentDot() pc.x = x * S pc.y = y * S self.scene.add(pc) self.add(Sprite(self.surf, 0)) + for y, line in enumerate(self.graph): + for x, node in enumerate(line): + if node is None: + continue + node.neighbors[Direction.LEFT.value] = \ + self.graph[y][(x-1)%w] + node.neighbors[Direction.RIGHT.value] = \ + self.graph[y][(x+1)%w] + node.neighbors[Direction.UP.value] = \ + self.graph[(y-1)%h][x] + node.neighbors[Direction.DOWN.value] = \ + self.graph[(y+1)%h][x] diff --git a/scenes/game_objects/pacman.py b/scenes/game_objects/pacman.py index bc7dc3a..c373d35 100644 --- a/scenes/game_objects/pacman.py +++ b/scenes/game_objects/pacman.py @@ -16,9 +16,10 @@ class PacMan(Entity): def __init__(self, x, y): super().__init__('pacman') - surf_1 = image.load(res('pacman_1.png')).convert() - surf_2 = image.load(res('pacman_2.png')).convert() + self.x = x + self.y = y + # Surface quand on est petit. self.smol_surf = Surface((S//2, S//2)).convert() self.smol_surf.fill((0, 0, 0)) draw.circle(self.smol_surf, @@ -26,6 +27,10 @@ class PacMan(Entity): (S//4, S//4), S//4) + # Surfaces pour chaque direction, pour chaque état de + # l’animation. + surf_1 = image.load(res('pacman_1.png')).convert() + surf_2 = image.load(res('pacman_2.png')).convert() self.surf = [[transform.rotate(surf_1, 90), transform.rotate(surf_1, -90), transform.flip(surf_1, True, False), @@ -35,14 +40,18 @@ class PacMan(Entity): transform.flip(surf_2, True, False), surf_2]] + # État d’animation courant. self.cur_anim = 0 self.sprite = self.add(Sprite(self.surf[self.cur_anim][0], 2)) + # Rectangle quand on est petit. self.smol_rect = Rect(self.x, self.y, self.sprite.width//2, self.sprite.width//2) + self.rect = Rect(self.x, self.y, self.sprite.width, self.sprite.width) + self.phys = CollideRect(self.rect, static=False, cb=self.cb) @@ -50,17 +59,18 @@ class PacMan(Entity): self.add(self.phys) self.script = PacMan.update - self.x = x - self.y = y self.smol = False self.smol_since = None def cb(self, c): if not isinstance(c.parent, EnsmallmentDot): return + # On a mangé une graine de rapetissement. if not self.smol: + # Décalage au milieu du couloir self.x += S//4 self.y += S//4 + PacMan.SPEED *= 2 self.smol_rect.x = self.x self.smol_rect.y = self.y @@ -72,22 +82,24 @@ class PacMan(Entity): p = self.phys s = self.sprite - # Expiration du pouvoir + # Expiration du rapetissement. if self.smol and Game.cur_tick - self.smol_since > 60*2: + # On se réaligne dans le couloir. self.x -= self.x % S self.y -= self.y % S + self.rect.x = self.x self.rect.y = self.y self.phys.rect = self.rect self.smol = False PacMan.SPEED = PacMan.SPEED//2 - # Avance l’animation + # Avance l’état d’animation. if Game.cur_tick % 5 == 0: self.cur_anim += 1 self.cur_anim %= 2 - # Nouvelle sprite + # Choix de la surface en fonction de la direction effective. if p.vy < 0: s.surf = self.surf[self.cur_anim][0] elif p.vy > 0: @@ -102,6 +114,8 @@ class PacMan(Entity): inputs = key.get_pressed() if self.smol: + # Quand on est petit on n’a pas de maintient de la + # vitesse. p.vx = 0 p.vy = 0 if inputs[K_UP]: diff --git a/scenes/lvl0.py b/scenes/lvl0.py index de8aa9d..59375a8 100644 --- a/scenes/lvl0.py +++ b/scenes/lvl0.py @@ -11,9 +11,9 @@ class Lvl0(Scene): self.add(Level('lvl0.png')) self.add(PacMan(S, S)) self.add(Ghost(S*6, S*2)) - self.add(Ghost(S*6, S*13)) - self.add(Ghost(S*18, S*13)) - self.add(Ghost(S*8, S*23)) + # self.add(Ghost(S*6, S*13)) + # self.add(Ghost(S*18, S*13)) + # self.add(Ghost(S*8, S*23)) super().load() diff --git a/scenes/lvl0_fantome.py b/scenes/lvl0_fantome.py deleted file mode 100644 index 4e809b4..0000000 --- a/scenes/lvl0_fantome.py +++ /dev/null @@ -1,171 +0,0 @@ -from engine.scene import Scene - - -S=20 - - -entities=[] - - -class PacDot(Entity): - s = Surface((S, S)) - draw.circle(s, (255, 255, 0), (S//2, S//2), S//4) - - def __init__(self): - super().__init__() - CollideRect(self, Rect(0, 0, S, S), - static=True, solid=False, cb=self.cb) - Sprite(self, PacDot.s, 1) - - def cb(self): - self.unregister() - - -def path(start, tgt, x, y, trace, length): - if start == tgt: - return length - if start is None or trace[y][x]: - return False - trace[y][x] = True - u = path(start.up, tgt, x, y-1, trace, length + 1) - d = path(start.down, tgt, x, y+1, trace, length + 1) - l = path(start.left, tgt, x-1, y, trace, length + 1) - r = path(start.right, tgt, x+1, y, trace, length + 1) - best = None - for subpath in (u, d, l, r): - if subpath and (best is None or subpath < best): - best = subpath - return best - - -class Node(): - cpt = 0 - def __init__(self): - self.id = self.__class__.cpt - self.__class__.cpt += 1 - self.up = None - self.down = None - self.left = None - self.right = None - def children(self): - children = [] - for direction in ("up", "down", "left", "right"): - node = getattr(self, direction) - if node is not None: - children.append((node, direction)) - return children - - - -graph = None - - -class Level(Entity): - def __init__(self, path): - global graph - super().__init__() - desc = image.load(res(path)) - w, h = desc.get_size() - GraphicsServer().resize((w * S, h * S)) - graph = [[None for x in range(w)] for y in range(h)] - self.surf = Surface((w * S, h * S)).convert() - self.surf.fill((0, 0, 0)) - wall = Surface((S, S)).convert() - wall.fill((0, 0, 255)) - for x, y in product(range(w), range(h)): - col = desc.get_at((x, y)) - if col == (0, 0, 255): - CollideRect(self, Rect(x * S, y * S, S, S)) - self.surf.blit(wall, (x * S, y * S)) - elif col == (139, 139, 139): - pc = PacDot() - pc.x = x * S - pc.y = y * S - entities.append(pc) - graph[y][x] = Node() - elif col == (0, 0, 0) or col == (255, 0, 0): - graph[y][x] = Node() - for y, line in enumerate(graph): - for x, node in enumerate(line): - if node is None: - continue - node.left = graph[y][(x-1)%w] - node.right = graph[y][(x+1)%w] - node.up = graph[(y-1)%h][x] - node.down = graph[(y+1)%h][x] - Sprite(self, self.surf, 0) - - -class MovingEntity(Entity): - def __init__(self, surf): - super().__init__() - sprite = Sprite(self, surf, 2) - self.phys = CollideRect( - self, - Rect(self.x, self.y, sprite.width, sprite.width), - static=False) - - -class Ghost(MovingEntity): - def __init__(self): - super().__init__(image.load(res('ghost.png')).convert()) - self.script = Ghost.script - - def script(self): - cur_node = graph[self.y//S][self.x//S] - print(self.y//S, self.x//S) - pacman = SceneManager().scene.entities['pacman'] - # pacman_node = graph[pacman.y//S][pacman.x//S] - x_dist = pacman.x - self.x - y_dist = pacman.y - self.y - s = 1 - # self.phys.vx = s if x_dist > 0 else -s - # self.phys.vy = s if y_dist > 0 else -s - p = self.find_shortest_path(graph[pacman.y//S][pacman.x//S]) - print([x[1] for x in p]) - cur_dir = p[0][1] - if cur_dir == "up": - self.phys.vx = 0 - self.phys.vy = -1 - elif cur_dir == "down": - self.phys.vx = 0 - self.phys.vy = 1 - elif cur_dir == "left": - self.phys.vx = -1 - self.phys.vy = 0 - else: - self.phys.vx = 1 - self.phys.vy = 0 - def find_shortest_path(self, final_node): - cur_node = graph[self.y//S][self.x//S] - # pacman_node = graph[pacman.y//S][pacman.x//S] - children = cur_node.children() - trace = [cur_node] + [x[0] for x in children] - # if self.phys.vx < 0: cur_dir = "left" - # elif self.phys.vx > 0: cur_dir = "right" - # elif self.phys.vy < 0: cur_dir = "up" - # else: cur_dir = "down" - paths = [[x] for x in children] - while 1: - cur_len = len(paths) - for path in paths[:cur_len]: - for child in path[-1][0].children(): - if child[0] is not None and child[0] not in trace: - trace.append(child[0]) - paths.append(path + [child]) - if child[0] == final_node: - return path - paths = paths[cur_len:] - -class Lvl0(Scene): - def load(self): - self.add(Level('lvl0.png')) - self.add(PacMan(S, S)) - self.add(Ghost(S*6, S*2)) - self.add(Ghost(S*6, S*13)) - self.add(Ghost(S*18, S*13)) - self.add(Ghost(S*8, S*23)) - super().load() - - -scene = Lvl0()