diff --git a/dungeonbattle/entities/monsters.py b/dungeonbattle/entities/monsters.py index 61a6ebf..161a3b1 100644 --- a/dungeonbattle/entities/monsters.py +++ b/dungeonbattle/entities/monsters.py @@ -17,20 +17,15 @@ class Monster(FightingEntity): target = entity break - if target: + # A Dijkstra algorithm has ran that targets the player. + # With that way, monsters can simply follow the path. + # If they can't move and they are already close to the player, + # They hit. + if target and (self.y, self.x) in target.paths: # Move to target player - y, x = self.vector(target) - if abs(y) > abs(x): # Move vertically - if y > 0: - self.move_down() - else: - self.move_up() - else: # Move horizontally - if x > 0: - self.move_right() - else: - self.move_left() - if self.distance_squared(target) <= 1: + next_y, next_x = target.paths[(self.y, self.x)] + moved = self.check_move(next_y, next_x, True) + if not moved and self.distance_squared(target) <= 1: self.hit(target) else: for _ in range(100): diff --git a/dungeonbattle/entities/player.py b/dungeonbattle/entities/player.py index 4e3affc..e9ba45f 100644 --- a/dungeonbattle/entities/player.py +++ b/dungeonbattle/entities/player.py @@ -1,4 +1,5 @@ from random import randint +from typing import Dict, Tuple from ..interfaces import FightingEntity @@ -14,6 +15,7 @@ class Player(FightingEntity): level: int = 1 current_xp: int = 0 max_xp: int = 10 + paths: Dict[Tuple[int, int], Tuple[int, int]] def move(self, y: int, x: int) -> None: """ @@ -22,6 +24,7 @@ class Player(FightingEntity): super().move(y, x) self.map.currenty = y self.map.currentx = x + self.recalculate_paths() def level_up(self) -> None: """ @@ -61,3 +64,26 @@ class Player(FightingEntity): self.add_xp(randint(3, 7)) return True return super().check_move(y, x, move_if_possible) + + def recalculate_paths(self) -> None: + """ + Use Dijkstra algorithm to calculate best paths + for monsters to go to the player. + """ + queue = [(self.y, self.x)] + visited = [] + predecessors = {} + while queue: + y, x = queue.pop(0) + visited.append((y, x)) + for diff_y, diff_x in [(1, 0), (-1, 0), (0, 1), (0, -1)]: + new_y, new_x = y + diff_y, x + diff_x + if not 0 <= new_y < self.map.height or \ + not 0 <= new_x < self.map.width or \ + not self.map.tiles[y][x].can_walk() or \ + (new_y, new_x) in visited or \ + (new_y, new_x) in queue: + continue + predecessors[(new_y, new_x)] = (y, x) + queue.append((new_y, new_x)) + self.paths = predecessors