diff --git a/engine/components/collide_rect.py b/engine/components/collide_rect.py index 3ca7d8d..39a6133 100644 --- a/engine/components/collide_rect.py +++ b/engine/components/collide_rect.py @@ -3,21 +3,23 @@ from ..servers.physics import PhysicsServer class CollideRect(Component): - def __init__(self, parent, rect, static=True, solid=True, cb=None): - super().__init__(parent) + def __init__(self, rect, static=True, solid=True, cb=None): + super().__init__() self.rect = rect - def x_change_cb(x): - self.rect.x = x - def y_change_cb(y): - self.rect.y = y - parent.subscribe('x', x_change_cb) - parent.subscribe('y', y_change_cb) self.static = static self.solid = solid self.cb = cb self.vx = 0 self.vy = 0 + def load(self): + def x_change_cb(x): + self.rect.x = x + def y_change_cb(y): + self.rect.y = y + self.parent.subscribe('x', x_change_cb) + self.parent.subscribe('y', y_change_cb) + def register(self): PhysicsServer().register_component(self) diff --git a/engine/components/component.py b/engine/components/component.py index 9da54ce..4e8a434 100644 --- a/engine/components/component.py +++ b/engine/components/component.py @@ -2,9 +2,12 @@ from abc import abstractmethod class Component: - def __init__(self, parent): - self.parent = parent - self.parent.add(self) + def __init__(self): + self.parent = None + + @abstractmethod + def load(self): + pass @abstractmethod def register(self): diff --git a/engine/components/sprite.py b/engine/components/sprite.py index 0fbfca4..f176b21 100644 --- a/engine/components/sprite.py +++ b/engine/components/sprite.py @@ -3,8 +3,8 @@ from ..servers.graphics import GraphicsServer class Sprite(Component): - def __init__(self, parent, surf, z): - super().__init__(parent) + def __init__(self, surf, z): + super().__init__() self.surf = surf self.width = self.surf.get_width() self.z = z diff --git a/engine/entity.py b/engine/entity.py index 8252e78..3b6a1c8 100644 --- a/engine/entity.py +++ b/engine/entity.py @@ -1,15 +1,23 @@ from .observer import Observer class Entity(Observer): - def __init__(self): + def __init__(self, name): super().__init__() self._components = [] + self.name = name + self.scene = None self.x = 0 self.y = 0 self.script = None + def load(self): + pass + def add(self, component): + component.parent = self + component.load() self._components.append(component) + return component def register(self): for component in self._components: diff --git a/engine/game.py b/engine/game.py index da21da4..3dae30f 100644 --- a/engine/game.py +++ b/engine/game.py @@ -8,6 +8,8 @@ from .scene_manager import SceneManager class Game: + cur_tick = 0 + def __init__(self, start_scene): self._graphics_server = GraphicsServer() self._sound_server = SoundServer() @@ -26,4 +28,5 @@ class Game: self._physics_server.step() self._sound_server.step() self._graphics_server.step() + Game.cur_tick += 1 clock.tick(60) diff --git a/engine/scene.py b/engine/scene.py index ede4c0f..7a7ae3e 100644 --- a/engine/scene.py +++ b/engine/scene.py @@ -2,6 +2,11 @@ class Scene: def __init__(self): self.entities = {} + def add(self, entity): + self.entities[entity.name] = entity + entity.scene = self + entity.load() + def unload(self): for entity in self.entities.values(): entity.unregister() diff --git a/engine/servers/physics.py b/engine/servers/physics.py index 4f3b55e..bdcc2de 100644 --- a/engine/servers/physics.py +++ b/engine/servers/physics.py @@ -34,7 +34,9 @@ class PhysicsServer(Server): c = self._check_collide(d) if c is not None: if c.cb: - c.cb() + c.cb(d) + if d.cb: + d.cb(c) if c.solid: d.parent.x -= x_step d.vx = 0 @@ -44,7 +46,9 @@ class PhysicsServer(Server): c = self._check_collide(d) if c is not None: if c.cb: - c.cb() + c.cb(d) + if d.cb: + d.cb(c) if c.solid: d.parent.y -= y_step d.vy = 0 diff --git a/res/pacman_1.png b/res/pacman_1.png new file mode 100644 index 0000000..1357dcb Binary files /dev/null and b/res/pacman_1.png differ diff --git a/res/pacman_2.png b/res/pacman_2.png new file mode 100644 index 0000000..767a169 Binary files /dev/null and b/res/pacman_2.png differ diff --git a/scenes/__init__.py b/scenes/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/scenes/game_objects/__init__.py b/scenes/game_objects/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/scenes/game_objects/common.py b/scenes/game_objects/common.py new file mode 100644 index 0000000..2d34628 --- /dev/null +++ b/scenes/game_objects/common.py @@ -0,0 +1 @@ +S = 20 diff --git a/scenes/game_objects/ghost.py b/scenes/game_objects/ghost.py new file mode 100644 index 0000000..63116c2 --- /dev/null +++ b/scenes/game_objects/ghost.py @@ -0,0 +1,77 @@ +from enum import Enum +from random import random, randint + +from pygame import Surface, draw, Rect, image + +from engine.entity import Entity +from engine.resources import res +from engine.components.collide_rect import CollideRect +from engine.components.sprite import Sprite + +from .common import S +from .pacdot import PacDot + + +class Direction(Enum): + UP = 1 + DOWN = 2 + LEFT = 3 + RIGHT = 4 + + +class Ghost(Entity): + SPEED = 1 + + def __init__(self, x, y): + super().__init__(self.__repr__()) + sprite = Sprite(image.load(res('ghost.png')).convert(), 2) + self.add(sprite) + self.phys = CollideRect(Rect(self.x, self.y, + sprite.width, sprite.width), + static=False, + solid=False, + cb=self.on_col) + self.add(self.phys) + self.script = Ghost.script + self.x = x + self.y = y + self.direction = Direction(randint(1, 4)) + + def on_col(self, c): + if isinstance(c.parent, PacDot): + return + + if c.parent.name == 'pacman': + print('Perdu !') + exit(0) + + if self.direction == Direction.UP: + self.direction = Direction.RIGHT if random() < .5 \ + else Direction.LEFT + return + if self.direction == Direction.RIGHT: + self.direction = Direction.DOWN if random() < .5 \ + else Direction.UP + return + if self.direction == Direction.DOWN: + self.direction = Direction.LEFT if random() < .5 \ + else Direction.RIGHT + return + if self.direction == Direction.LEFT: + self.direction = Direction.UP if random() < .5 \ + else Direction.DOWN + return + + def script(self): + if self.direction == Direction.UP: + self.phys.vy = -Ghost.SPEED + self.phys.vx = 0 + elif self.direction == Direction.DOWN: + self.phys.vy = Ghost.SPEED + self.phys.vx = 0 + elif self.direction == Direction.LEFT: + self.phys.vx = -Ghost.SPEED + self.phys.vy = 0 + elif self.direction == Direction.RIGHT: + self.phys.vx = Ghost.SPEED + self.phys.vy = 0 diff --git a/scenes/game_objects/level.py b/scenes/game_objects/level.py new file mode 100644 index 0000000..2bda6bd --- /dev/null +++ b/scenes/game_objects/level.py @@ -0,0 +1,39 @@ +from itertools import product + +from pygame import Surface, Rect, image + +from engine.entity import Entity +from engine.resources import res +from engine.servers.graphics import GraphicsServer +from engine.components.collide_rect import CollideRect +from engine.components.sprite import Sprite + +from .common import S +from .pacdot import PacDot + + +class Level(Entity): + def __init__(self, path): + super().__init__('level') + self.path = path + + def load(self): + desc = image.load(res(self.path)) + w, h = desc.get_size() + GraphicsServer().resize((w * S, h * S)) + 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): + self.add(CollideRect(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 + self.scene.add(pc) + PacDot.tot += 1 + self.add(Sprite(self.surf, 0)) diff --git a/scenes/game_objects/pacdot.py b/scenes/game_objects/pacdot.py new file mode 100644 index 0000000..174179a --- /dev/null +++ b/scenes/game_objects/pacdot.py @@ -0,0 +1,34 @@ +from pygame import Surface, draw, Rect + +from engine.entity import Entity +from engine.components.collide_rect import CollideRect +from engine.components.sprite import Sprite + +from .common import S +from .pacman import PacMan + + +class PacDot(Entity): + tot = 0 + s = Surface((S, S)) + draw.circle(s, (255, 255, 0), (S//2, S//2), S//4) + + def __init__(self): + super().__init__(self.__repr__()) + self.add(CollideRect(Rect(0, 0, S, S), + static=True, solid=False, cb=self.cb)) + self.add(Sprite(PacDot.s, 1)) + self.dead = False + + def cb(self, c): + if c.parent.name != 'pacman': + return + if self.dead: + return + self.dead = True + PacDot.tot -= 1 + if PacDot.tot == 0: + print('Gagné !') + exit(0) + if c.parent.name == 'pacman': + self.unregister() diff --git a/scenes/game_objects/pacman.py b/scenes/game_objects/pacman.py new file mode 100644 index 0000000..7285708 --- /dev/null +++ b/scenes/game_objects/pacman.py @@ -0,0 +1,80 @@ +from pygame import Surface, draw, Rect, key, image, transform +from pygame.locals import K_UP, K_DOWN, K_LEFT, K_RIGHT + +from engine.entity import Entity +from engine.game import Game +from engine.resources import res +from engine.components.collide_rect import CollideRect +from engine.components.sprite import Sprite + +from .common import S + + +class PacMan(Entity): + SIZE = 1 + SPEED = 2 + + def __init__(self, x, y): + super().__init__('pacman') + + # surf = Surface((S//PacMan.SIZE, S//PacMan.SIZE)).convert() + # surf.fill((0, 0, 0)) + # draw.circle(surf, + # (255, 255, 0), + # (S//(2*PacMan.SIZE), S//(2*PacMan.SIZE)), + # S//(2*PacMan.SIZE)) + 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), + surf_1], + [transform.rotate(surf_2, 90), + transform.rotate(surf_2, -90), + transform.flip(surf_2, True, False), + surf_2]] + + self.cur_anim = 0 + + self.sprite = self.add(Sprite(self.surf[self.cur_anim][0], 2)) + + self.phys = self.add( + CollideRect(Rect(self.x, self.y, + self.sprite.width, self.sprite.width), + static=False)) + self.script = PacMan.update + self.x = x + self.y = y + + def update(self): + p = self.phys + s = self.sprite + + # Avance l’animation + if Game.cur_tick % 5 == 0: + self.cur_anim += 1 + self.cur_anim %= 2 + + # Nouvelle sprite + if p.vy < 0: + s.surf = self.surf[self.cur_anim][0] + elif p.vy > 0: + s.surf = self.surf[self.cur_anim][1] + elif p.vx < 0: + s.surf = self.surf[self.cur_anim][2] + elif p.vx > 0: + s.surf = self.surf[self.cur_anim][3] + + inputs = key.get_pressed() + if PacMan.SIZE > 1: + p.vx = 0 + p.vy = 0 + if inputs[K_UP]: + p.vy = -PacMan.SPEED + if inputs[K_DOWN]: + p.vy = PacMan.SPEED + if inputs[K_LEFT]: + p.vx = -PacMan.SPEED + if inputs[K_RIGHT]: + p.vx = PacMan.SPEED diff --git a/scenes/lvl0.py b/scenes/lvl0.py index 09e4614..de8aa9d 100644 --- a/scenes/lvl0.py +++ b/scenes/lvl0.py @@ -1,169 +1,19 @@ -from engine.resources import res from engine.scene import Scene -from engine.entity import Entity -from engine.components.sprite import Sprite -from engine.components.collide_rect import CollideRect -from engine.servers.graphics import GraphicsServer -from engine.scene_manager import SceneManager -from pygame import Rect -from pygame import image -from pygame import Surface -from pygame import draw -from pygame.locals import * -from pygame import key -from itertools import product - -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(): - def __init__(self): - self.up = None - self.down = None - self.left = None - self.right = None - - -graph = None - - -class Level(Entity): - def __init__(self, path): - 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) - # elif col == (0, 0, 0): - # graph[y][x] = Node() - # for y, line in enumerate(graph): - # for x, node in enumerate(line): - # if node is None: - # continue - # if x > 0: - # node.left = graph[y][x-1] - # if x < w: - # node.right = graph[y][x+1] - # if y > 0: - # node.up = graph[y-1][x] - # if y < h: - # node.down = graph[y+1][y] - 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] - 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 +from .game_objects.common import S +from .game_objects.level import Level +from .game_objects.pacman import PacMan +from .game_objects.ghost import Ghost class Lvl0(Scene): def load(self): - T = 1 - v = 2 - - pac_surf = Surface((S//T, S//T)).convert() - pac_surf.fill((0, 0, 0)) - draw.circle(pac_surf, (255, 255, 0), (S//(2*T), S//(2*T)), S//(2*T)) - pacman = MovingEntity(pac_surf) - def pacman_script(entity): - p = pacman.phys - inputs = key.get_pressed() - if T > 1: - p.vx = 0 - p.vy = 0 - if inputs[K_UP]: - p.vy = -v - if inputs[K_DOWN]: - p.vy = v - if inputs[K_LEFT]: - p.vx = -v - if inputs[K_RIGHT]: - p.vx = v - pacman.script = pacman_script - pacman.x = pacman.phys.rect.x = S*1 - pacman.y = pacman.phys.rect.y = S*1 - - pacman.phys.rect.w = S//T - pacman.phys.rect.h = S//T - - self.entities['level'] = Level('lvl0.png') - for i, entity in enumerate(entities): - self.entities[f'pacdot-{i}'] = entity - self.entities['pacman'] = pacman - self.entities['ghost'] = Ghost() - self.entities['ghost'].x = S*6 - self.entities['ghost'].y = S*2 - + 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()