import pygame import random from settings import * vec = pygame.math.Vector2 class Ghosts: def __init__(self, app, pos, id): self.app = app self.grid_pos = pos self.pix_pos = self.get_pix_pos() self.radius = self.app.cell_width//2 self.id = id self.color = self.set_color() self.direction = vec(1, 0) self.type = self.set_type() self.speed = self.set_speed() self.target = self.app.player.grid_pos self.starting_point = [pos.x, pos.y] print(self.type) def update(self): self.target = self.pick_target() if self.target != self.grid_pos: self.pix_pos += self.direction * self.speed if self.time_to_move(): self.move() # Updates the grid position, same as player class self.grid_pos[0] = (self.pix_pos[0] - BUFFERS // 2 + self.app.cell_width // 2) // self.app.cell_width self.grid_pos[1] = (self.pix_pos[1] - BUFFERS // 2 + self.app.cell_height // 2) // self.app.cell_height # ###################################### Helper Functions ####################################### def get_pix_pos(self): return vec((self.grid_pos.x * self.app.cell_width) + BUFFERS // 2 + self.app.cell_width // 2, (self.grid_pos.y * self.app.cell_height) + BUFFERS // 2 + self.app.cell_height // 2) def draw(self): pygame.draw.circle(self.app.screen, self.color, (int(self.pix_pos.x+5), int(self.pix_pos.y+2.3)), self.app.cell_width//2) # set's each ghost's speed def set_speed(self): if self.type == "fast": speed = 1.03 elif self.type == "slow": speed = .5 elif self.type == "vari": num = random.randint(-2, 1) if num == -2: speed = 1.15 elif num == -1: speed = 1 else: speed = .75 else: speed = 1 return speed # ###################################### Movement Functions ####################################### # same as player movment def time_to_move(self): if int(self.pix_pos.x + BUFFERS // 2) % self.app.cell_width == 0: if self.direction == vec(1, 0) or self.direction == vec(-1, 0) or self.direction == vec(0, 0): return True if int(self.pix_pos.y+BUFFERS//2) % self.app.cell_height == 0: if self.direction == vec(0, 1) or self.direction == vec(0, -1) or self.direction == vec(0, 0): return True return False # calls the appropriate functions for each ghost type def move(self): if self.type == "random": self.direction = self.get_random_direction() if self.type == "fast": self.direction = self.get_next_path(self.target) if self.type == "vari": self.set_speed() self.direction = self.get_next_path(self.target) if self.type == "scaredy": self.direction = self.get_next_path(self.target) # ###################################### Ghost Setup Functions ####################################### # assigns colors to each ghost based on ID in the map data def set_color(self): if self.id == 0: return RED elif self.id == 1: return BLUE elif self.id == 2: return ORANGE elif self.id == 3: return PINK # assigns each ghost a type based on their ID in the map data def set_type(self): if self.id == 0: return "random" elif self.id == 1: return "fast" elif self.id == 2: return "vari" elif self.id == 3: return "scaredy" # ###################################### Path Making Functions ####################################### # finds target, vari and fast find player # scaredy finds the opposite corner of the player's quadrant def pick_target(self): if self.type == "vari" or self.type == "fast": return self.app.player.grid_pos else: if self.app.player.grid_pos[0] > COL // 2 and self.app.player.grid_pos[1] > ROW // 2: return vec(1, 1) if self.app.player.grid_pos[0] > COL // 2 and self.app.player.grid_pos[1] < ROW // 2: return vec(1, ROW - 2) if self.app.player.grid_pos[0] < COL // 2 and self.app.player.grid_pos[1] > ROW // 2: return vec(COL - 2, 1) else: return vec(COL - 2, ROW - 2) # finds next path through a breadth first search def find_next(self, target): # print("data1: ", [int(self.grid_pos.x), int(self.grid_pos.y)], "data 2: ", # [int(self.app.player.grid_pos.x), int(self.app.player.grid_pos.y)]) path = self.BFS([int(self.grid_pos.x), int(self.grid_pos.y)], [int(target[0]), int(target[1])]) # print("path[1]: ", path[1]) return path[1] # sets next cell for ghost based on grid position def get_next_path(self, target): # print("in get_next_path") next_cell = self.find_next(target) # print("Next cell: ", next_cell) x_dir = next_cell[0] - self.grid_pos[0] y_dir = next_cell[1] - self.grid_pos[1] return vec(x_dir, y_dir) # selects a random direction based on the randomly chosen number def get_random_direction(self): while True: num = random.randint(-2, 1) if num == -2: x_dir, y_dir = 1, 0 elif num == -1: x_dir, y_dir = 0, 1 elif num == 0: x_dir, y_dir = -1, 0 else: x_dir, y_dir = 0, -1 next_pos = vec(self.grid_pos.x + x_dir, self.grid_pos.y + y_dir) if next_pos not in self.app.walls: break return vec(x_dir, y_dir) # conducts a breadth first search through the grid, checking path's to find the # shortest possible path to the ghost's target def BFS(self, start, target): # print("in BFS") grid = [[0 for x in range(56)] for x in range(48)] for cell in self.app.walls: if cell.x < 56 and cell.y < 48: grid[int(cell.y)][int(cell.x)] = 1 # print("thing:") # for cell in grid: # print(cell, " ") queue = [start] path = [] visited = [] while queue: # print("******In While******") current = queue[0] queue.remove(queue[0]) visited.append(current) # print("queue: ", queue, "current: ", current, "target: ", target) if current == target: # print("FOUND TARGET @: ", current) break else: neighbours = [[0, -1], [1, 0], [0, 1], [-1, 0]] for neighbour in neighbours: if 0 <= neighbour[0] + current[0] < len(grid[0]): # print("if 1") if 0 <= neighbour[1] + current[1] < len(grid): # print("if 2") next_cell = [neighbour[0] + current[0], neighbour[1] + current[1]] # print("grid of pos: ", grid[next_cell[1]][next_cell[0]]) # print("---------") if next_cell not in visited: # print("if 3") if grid[next_cell[1]][next_cell[0]] != 1: # print("if 4") queue.append(next_cell) # print("Queue in if 4: ", queue) path.append({"Current": current, "Next": next_cell}) shortest = [target] while target != start: for step in path: # print("next: ", step["Next"]) if step["Next"] == target: target = step["Current"] shortest.insert(0, step["Current"]) # print("Shortest: ", shortest) return shortest