Pygame Pacman - Enemy Random Movement

巧了我就是萌 提交于 2021-02-15 07:14:32

问题


Ive made a pacman game using python and pygame and I have one of the ghosts that just makes random movements around the maze. Does anyone know if there is a way for me to make the random enemy more AI controlled? I still want it to be random but at the moment the random movement code I have makes it so that the ghost can sometimes get stuck in the box that the ghosts start in or it will just go back and forth from one place to another.

This is the Random movement method that I Have:

def get_random_direction(self):
            while True:
                number = random.randint(-2, 1)
                if number == -2:
                    x_dir, y_dir = 1, 0
                elif number == -1:
                    x_dir, y_dir = 0, 1
                elif number == 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)

I assume the code above is the part that I will need to edit for the random movement to be changed I just don't know what to do to change it.

this is the full class for my enemies that holds all the code used by the enemies:

        import pygame
    import random
    from settings import *

    vec = pygame.math.Vector2


    class Enemy:
        def __init__(self, app, pos, number):
            self.app = app
            self.grid_pos = pos
            self.starting_pos = [pos.x, pos.y]
            self.pix_pos = self.get_pix_pos()
            self.radius = int(self.app.cell_width//2.3)
            self.number = number
            self.colour = self.set_colour()
            self.direction = vec(0, 0)
            self.personality = self.set_personality()
            self.target = None
            self.speed = self.set_speed()

        def update(self):
            self.target = self.set_target()
            if self.target != self.grid_pos:
                self.pix_pos += self.direction * self.speed
                if self.time_to_move():
                    self.move()

            # Setting grid position in reference to pix position
            self.grid_pos[0] = (self.pix_pos[0]-TOP_BOTTOM_BUFFER +
                                self.app.cell_width//2)//self.app.cell_width+1
            self.grid_pos[1] = (self.pix_pos[1]-TOP_BOTTOM_BUFFER +
                                self.app.cell_height//2)//self.app.cell_height+1

        def draw(self):
            pygame.draw.circle(self.app.screen, self.colour,
                               (int(self.pix_pos.x), int(self.pix_pos.y)), self.radius)

        def set_speed(self):
            if self.personality in ["rapid", "frightened"]:
                speed = 1
            else:
                speed = 0.90
            return speed

        def set_target(self):
            if self.personality == "rapid" or self.personality == "sluggish":
                return self.app.player.grid_pos
            else:
                if self.app.player.grid_pos[0] > COLS//2 and self.app.player.grid_pos[1] > ROWS//2:
                    return vec(1, 1)
                if self.app.player.grid_pos[0] > COLS//2 and self.app.player.grid_pos[1] < ROWS//2:
                    return vec(1, ROWS-2)
                if self.app.player.grid_pos[0] < COLS//2 and self.app.player.grid_pos[1] > ROWS//2:
                    return vec(COLS-2, 1)
                else:
                    return vec(COLS-2, ROWS-2)

        def time_to_move(self):
            if int(self.pix_pos.x+TOP_BOTTOM_BUFFER//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+TOP_BOTTOM_BUFFER//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

        def move(self):
            if self.personality == "random":
                self.direction = self.get_random_direction()
            if self.personality == "sluggish":
                self.direction = self.get_path_direction(self.target)
            if self.personality == "rapid":
                self.direction = self.get_path_direction(self.target)
            if self.personality == "frightened":
                self.direction = self.get_path_direction(self.target)

        def get_path_direction(self, target):
            next_cell = self.find_next_cell_in_path(target)
            xdir = next_cell[0] - self.grid_pos[0]
            ydir = next_cell[1] - self.grid_pos[1]
            return vec(xdir, ydir)

        def find_next_cell_in_path(self, target):
            path = self.BFS([int(self.grid_pos.x), int(self.grid_pos.y)], [
                            int(target[0]), int(target[1])])
            return path[1]

        def BFS(self, start, target):
            grid = [[0 for x in range(28)] for x in range(30)]
            for cell in self.app.walls:
                if cell.x < 28 and cell.y < 30:
                    grid[int(cell.y)][int(cell.x)] = 1
            queue = [start]
            path = []
            visited = []
            while queue:
                current = queue[0]
                queue.remove(queue[0])
                visited.append(current)
                if current == target:
                    break
                else:
                    neighbours = [[0, -1], [1, 0], [0, 1], [-1, 0]]
                    for neighbour in neighbours:
                        if neighbour[0]+current[0] >= 0 and neighbour[0] + current[0] < len(grid[0]):
                            if neighbour[1]+current[1] >= 0 and neighbour[1] + current[1] < len(grid):
                                next_cell = [neighbour[0] + current[0], neighbour[1] + current[1]]
                                if next_cell not in visited:
                                    if grid[next_cell[1]][next_cell[0]] != 1:
                                        queue.append(next_cell)
                                        path.append({"Current": current, "Next": next_cell})
            shortest = [target]
            while target != start:
                for step in path:
                    if step["Next"] == target:
                        target = step["Current"]
                        shortest.insert(0, step["Current"])
            return shortest

        def get_random_direction(self):
            while True:
                number = random.randint(-2, 1)
                if number == -2:
                    x_dir, y_dir = 1, 0
                elif number == -1:
                    x_dir, y_dir = 0, 1
                elif number == 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)

        def get_pix_pos(self):
            return vec((self.grid_pos.x*self.app.cell_width)+TOP_BOTTOM_BUFFER//2+self.app.cell_width//2,
                       (self.grid_pos.y*self.app.cell_height)+TOP_BOTTOM_BUFFER//2 +
                       self.app.cell_height//2)

        def set_colour(self):
            if self.number == 0:
                return (52, 235, 61)
            if self.number == 1:
                return (3, 242, 255)
            if self.number == 2:
                return (255, 158, 3)
            if self.number == 3:
                return (255, 3, 3)

        def set_personality(self):
            if self.number == 0:
                return "rapid"
            elif self.number == 1:
                return "sluggish"
            elif self.number == 2:
                return "random"
            else:
                return "frightened"

回答1:


A possible improvement could be to keep the direction for a certain distance. Add an attribute for the current direction and number of steps. Keep the direction as long as there are steps left and the enemy doesn't hit a wall:

class Enemy:
    def __init__(self):
        # [...]

        self.dir = (0, 0)
        self.steps = 0

    def get_random_direction(self):
        self.steps -= 1
        if self.steps > 0:
            next_pos = vec(self.grid_pos.x + self.dir[0], self.grid_pos.y + self.dir[1])
            if next_pos not in self.app.walls:
                return vec(self.dir)

        possible_directions = []
        for dir_x, dir_y in [(1, 0), (0, 1), (-1, 0), (0, -1)]:
            next_pos = vec(self.grid_pos.x + dir_x, self.grid_pos.y + dir_y)
            if next_pos not in self.app.walls:
                possible_directions.append((dir_x, dir_y))

        self.steps = random.randint(3, 10)
        self.dir = random.choice(possible_directions)
        return vec(self.dir)


来源:https://stackoverflow.com/questions/65305293/pygame-pacman-enemy-random-movement

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!