问题
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