intégration de la recherche de chemin super intélligente

This commit is contained in:
papush! 2019-12-09 15:29:35 +01:00
parent 5c6f690a98
commit a235f8f77e
6 changed files with 114 additions and 194 deletions

View File

@ -1 +1,11 @@
from enum import Enum
S = 20 S = 20
class Direction(Enum):
UP = 0
DOWN = 1
LEFT = 2
RIGHT = 3

View File

@ -1,24 +1,17 @@
from enum import Enum
from random import random, randint from random import random, randint
from pygame import Surface, draw, Rect, image from pygame import Surface, draw, Rect, image
from engine.entity import Entity from engine.entity import Entity
from engine.scene_manager import SceneManager
from engine.resources import res from engine.resources import res
from engine.components.collide_rect import CollideRect from engine.components.collide_rect import CollideRect
from engine.components.sprite import Sprite from engine.components.sprite import Sprite
from .common import S from .common import S, Direction
from .pacdot import PacDot from .pacdot import PacDot
class Direction(Enum):
UP = 1
DOWN = 2
LEFT = 3
RIGHT = 4
class Ghost(Entity): class Ghost(Entity):
SPEED = 1 SPEED = 1
@ -30,14 +23,14 @@ class Ghost(Entity):
sprite.width, sprite.width), sprite.width, sprite.width),
static=False, static=False,
solid=False, solid=False,
cb=self.on_col) cb=self.cb)
self.add(self.phys) self.add(self.phys)
self.script = Ghost.script self.script = Ghost.script
self.x = x self.x = x
self.y = y 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: if not c.solid:
return return
@ -63,6 +56,30 @@ class Ghost(Entity):
return return
def script(self): 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: if self.direction == Direction.UP:
self.phys.vy = -Ghost.SPEED self.phys.vy = -Ghost.SPEED
self.phys.vx = 0 self.phys.vx = 0
@ -75,3 +92,20 @@ class Ghost(Entity):
elif self.direction == Direction.RIGHT: elif self.direction == Direction.RIGHT:
self.phys.vx = Ghost.SPEED self.phys.vx = Ghost.SPEED
self.phys.vy = 0 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:]

View File

@ -8,10 +8,27 @@ from engine.servers.graphics import GraphicsServer
from engine.components.collide_rect import CollideRect from engine.components.collide_rect import CollideRect
from engine.components.sprite import Sprite from engine.components.sprite import Sprite
from .common import S from .common import S, Direction
from .pacdot import PacDot, EnsmallmentDot 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): class Level(Entity):
def __init__(self, path): def __init__(self, path):
super().__init__('level') super().__init__('level')
@ -25,6 +42,7 @@ class Level(Entity):
self.surf.fill((0, 0, 0)) self.surf.fill((0, 0, 0))
wall = Surface((S, S)).convert() wall = Surface((S, S)).convert()
wall.fill((0, 0, 255)) 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)): for x, y in product(range(w), range(h)):
col = desc.get_at((x, y)) col = desc.get_at((x, y))
if col == (0, 0, 255): if col == (0, 0, 255):
@ -36,9 +54,24 @@ class Level(Entity):
pc.y = y * S pc.y = y * S
self.scene.add(pc) self.scene.add(pc)
PacDot.tot += 1 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): elif col == (193, 193, 193):
pc = EnsmallmentDot() pc = EnsmallmentDot()
pc.x = x * S pc.x = x * S
pc.y = y * S pc.y = y * S
self.scene.add(pc) self.scene.add(pc)
self.add(Sprite(self.surf, 0)) 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]

View File

@ -16,9 +16,10 @@ class PacMan(Entity):
def __init__(self, x, y): def __init__(self, x, y):
super().__init__('pacman') super().__init__('pacman')
surf_1 = image.load(res('pacman_1.png')).convert() self.x = x
surf_2 = image.load(res('pacman_2.png')).convert() self.y = y
# Surface quand on est petit.
self.smol_surf = Surface((S//2, S//2)).convert() self.smol_surf = Surface((S//2, S//2)).convert()
self.smol_surf.fill((0, 0, 0)) self.smol_surf.fill((0, 0, 0))
draw.circle(self.smol_surf, draw.circle(self.smol_surf,
@ -26,6 +27,10 @@ class PacMan(Entity):
(S//4, S//4), (S//4, S//4),
S//4) S//4)
# Surfaces pour chaque direction, pour chaque état de
# lanimation.
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), self.surf = [[transform.rotate(surf_1, 90),
transform.rotate(surf_1, -90), transform.rotate(surf_1, -90),
transform.flip(surf_1, True, False), transform.flip(surf_1, True, False),
@ -35,14 +40,18 @@ class PacMan(Entity):
transform.flip(surf_2, True, False), transform.flip(surf_2, True, False),
surf_2]] surf_2]]
# État danimation courant.
self.cur_anim = 0 self.cur_anim = 0
self.sprite = self.add(Sprite(self.surf[self.cur_anim][0], 2)) 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.smol_rect = Rect(self.x, self.y,
self.sprite.width//2, self.sprite.width//2) self.sprite.width//2, self.sprite.width//2)
self.rect = Rect(self.x, self.y, self.rect = Rect(self.x, self.y,
self.sprite.width, self.sprite.width) self.sprite.width, self.sprite.width)
self.phys = CollideRect(self.rect, self.phys = CollideRect(self.rect,
static=False, static=False,
cb=self.cb) cb=self.cb)
@ -50,17 +59,18 @@ class PacMan(Entity):
self.add(self.phys) self.add(self.phys)
self.script = PacMan.update self.script = PacMan.update
self.x = x
self.y = y
self.smol = False self.smol = False
self.smol_since = None self.smol_since = None
def cb(self, c): def cb(self, c):
if not isinstance(c.parent, EnsmallmentDot): if not isinstance(c.parent, EnsmallmentDot):
return return
# On a mangé une graine de rapetissement.
if not self.smol: if not self.smol:
# Décalage au milieu du couloir
self.x += S//4 self.x += S//4
self.y += S//4 self.y += S//4
PacMan.SPEED *= 2 PacMan.SPEED *= 2
self.smol_rect.x = self.x self.smol_rect.x = self.x
self.smol_rect.y = self.y self.smol_rect.y = self.y
@ -72,22 +82,24 @@ class PacMan(Entity):
p = self.phys p = self.phys
s = self.sprite s = self.sprite
# Expiration du pouvoir # Expiration du rapetissement.
if self.smol and Game.cur_tick - self.smol_since > 60*2: 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.x -= self.x % S
self.y -= self.y % S self.y -= self.y % S
self.rect.x = self.x self.rect.x = self.x
self.rect.y = self.y self.rect.y = self.y
self.phys.rect = self.rect self.phys.rect = self.rect
self.smol = False self.smol = False
PacMan.SPEED = PacMan.SPEED//2 PacMan.SPEED = PacMan.SPEED//2
# Avance lanimation # Avance létat danimation.
if Game.cur_tick % 5 == 0: if Game.cur_tick % 5 == 0:
self.cur_anim += 1 self.cur_anim += 1
self.cur_anim %= 2 self.cur_anim %= 2
# Nouvelle sprite # Choix de la surface en fonction de la direction effective.
if p.vy < 0: if p.vy < 0:
s.surf = self.surf[self.cur_anim][0] s.surf = self.surf[self.cur_anim][0]
elif p.vy > 0: elif p.vy > 0:
@ -102,6 +114,8 @@ class PacMan(Entity):
inputs = key.get_pressed() inputs = key.get_pressed()
if self.smol: if self.smol:
# Quand on est petit on na pas de maintient de la
# vitesse.
p.vx = 0 p.vx = 0
p.vy = 0 p.vy = 0
if inputs[K_UP]: if inputs[K_UP]:

View File

@ -11,9 +11,9 @@ class Lvl0(Scene):
self.add(Level('lvl0.png')) self.add(Level('lvl0.png'))
self.add(PacMan(S, S)) self.add(PacMan(S, S))
self.add(Ghost(S*6, S*2)) self.add(Ghost(S*6, S*2))
self.add(Ghost(S*6, S*13)) # self.add(Ghost(S*6, S*13))
self.add(Ghost(S*18, S*13)) # self.add(Ghost(S*18, S*13))
self.add(Ghost(S*8, S*23)) # self.add(Ghost(S*8, S*23))
super().load() super().load()

View File

@ -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()