Я сделал игру pacman, используя python и pygame, и у меня есть один из призраков, который просто совершает случайные движения по лабиринту. Кто-нибудь знает, есть ли способ сделать случайного врага более контролируемым ИИ? Я все еще хочу, чтобы это было случайным, но на данный момент код случайного движения, который у меня есть, делает так, что призрак может иногда застревать в коробке, в которой призраки начинают, или он просто будет перемещаться туда и обратно из одного места в другое.
Это метод случайного движения, который у меня есть:
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)
Я предполагаю, что приведенный выше код - это та часть, которую мне нужно будет отредактировать, чтобы изменить случайное движение, я просто не знаю, что делать, чтобы изменить его.
это полный класс для моих врагов, который содержит весь код, используемый врагами:
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"
@Rabbid76 правда, это работает не так, как я хотел, движение слишком случайное, если это имеет смысл, призрак может повернуть налево на 1 место, а затем сразу же вернуться туда, где он когда-либо, и может продолжать делать это целую вечность. он проходит, может быть, 2 пробела, а затем повторяет это снова. Мне нужно, чтобы движение было менее случайным и больше походило на настоящего врага.
Возможным улучшением может быть сохранение направления на определенном расстоянии. Добавьте атрибут для текущего направления и количества шагов. Сохраняйте направление до тех пор, пока остаются шаги и враг не ударяется о стену:
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)
внизу подразумевается возврат возврата?
или только один возврат
Код выглядит нормально. Это работает, не так ли? Ваш вопрос из разряда: Пожалуйста, помогите мне сделать его лучше и красивее. Но вы не указываете ожидаемое поведение. Вы просто говорите, что вам не нравится то, как оно есть. Вам очень трудно помочь, и нет смысла задавать один и тот же вопрос снова и снова.