如何防止玩家在 pygame 的迷宫中穿过墙壁? [英] How do I prevent the player from moving through the walls in a maze in pygame?

查看:22
本文介绍了如何防止玩家在 pygame 的迷宫中穿过墙壁?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个按网格组织的迷宫.网格的每个单元格都存储有关其右侧和底部相邻单元格的墙壁的信息.玩家是一个特定大小的物体,其边界框是已知的.我想让玩家顺利通过迷宫,墙壁阻止他们通过.

最小且可重复的示例:

导入pygame,随机类迷宫:def __init__(self, rows = 9, columns = 9):self.size =(列,行)self.walls = [[[True, True] for _ in range(self.size[1])] for __ in range(self.size[0])]访问 = [[False for _ in range(self.size[1])] for __ in range(self.size[0])]i, j = (self.size[0]+1)//2, (self.size[1]+1)//2访问过[i][j] = 真堆栈 = [(i, j)]而堆栈:当前 = stack.pop()i, j = 当前nl = [n for n in [(i-1, j), (i+1, j), (i, j-1), (i, j+1)]如果 0 <= n[0] 

解决方案

实现简单的逻辑,当玩家移动时测试玩家路径中是否有墙.检测到与墙壁发生碰撞时放弃移动.

Maze 类添加方法来检查单元格与其相邻单元格之间的墙:

类迷宫:# [...]def wall_left(self, i, j):返回 i <1 或 self.walls[i-1][j][0]def wall_right(self, i, j):返回 i >= self.size[0] 或 self.walls[i][j][0]def wall_top(self, i, j):返回 j <1 或 self.walls[i][j-1][1]def wall_bottom(self, i, j):返回 j >= self.size[0] 或 self.walls[i][j][1]

计算玩家边界框角点的行和列.

i0 = (player_rect.left - maze_pos[0])//cell_sizei1 = (player_rect.right - maze_pos[0])//cell_sizej0 = (player_rect.top - maze_pos[1])//cell_sizej1 = (player_rect.bottom - maze_pos[1])//cell_size

当玩家移动时,测试玩家是否正在进入一个新的单元格.使用Maze 类中的新方法来测试玩家路径中是否有墙.如果路径被墙挡住,则跳过移动:

keys = pygame.key.get_pressed()如果键[pygame.K_LEFT]:new_rect = player_rect.move(-3, 0)ni = (new_rect.left - maze_pos[0])//cell_size如果 i0 == ni 或不 (maze.wall_left(i0, j0) or maze.wall_left(i0, j1) or (j0 != j1 and maze.wall_bottom(ni, j0))):player_rect = new_rect如果键[pygame.K_RIGHT]:new_rect = player_rect.move(3, 0)ni = (new_rect.right - maze_pos[0])//cell_size如果 i1 == ni 或不 (maze.wall_right(i1, j0) or maze.wall_right(i1, j1) or (j0 != j1 and maze.wall_bottom(ni, j0))):player_rect = new_rect键 = pygame.key.get_pressed()如果键[pygame.K_UP]:new_rect = player_rect.move(0, -3)nj = (new_rect.top - maze_pos[1])//cell_size如果 j0 == nj 或不 (maze.wall_top(i0, j0) or maze.wall_top(i1, j0) or (i0 != i1 and maze.wall_right(i0, nj))):player_rect = new_rect如果键[pygame.K_DOWN]:new_rect = player_rect.move(0, 3)nj = (new_rect.bottom - maze_pos[1])//cell_size如果 j1 == nj 或不(maze.wall_bottom(i0, j1) or maze.wall_bottom(i1, j1) or (i0 != i1 and maze.wall_right(i0, nj))):player_rect = new_rect

另见

导入pygame,随机类迷宫:def __init__(self, rows = 9, columns = 9):self.size =(列,行)self.walls = [[[True, True] for _ in range(self.size[1])] for __ in range(self.size[0])]访问 = [[False for _ in range(self.size[1])] for __ in range(self.size[0])]i, j = (self.size[0]+1)//2, (self.size[1]+1)//2访问过[i][j] = 真堆栈 = [(i, j)]而堆栈:当前 = stack.pop()i, j = 当前nl = [n for n in [(i-1, j), (i+1, j), (i, j-1), (i, j+1)]如果 0 <= n[0] = self.size[0] 或 self.walls[i][j][0]def wall_top(self, i, j):返回 j <1 或 self.walls[i][j-1][1]def wall_bottom(self, i, j):返回 j >= self.size[0] 或 self.walls[i][j][1]def draw_maze(冲浪,迷宫,x,y,l,颜色,宽度):行 = [((x, y), (x + l * len(maze.walls), y)), ((x, y), (x, y + l * len(maze.walls[0])))]对于 i,在 enumerate(maze.walls) 中排行:对于 j,枚举(行)中的单元格:如果单元格[0]:行 += [((x + i*l + l, y + j*l), (x + i*l + l, y + j*l + l))]如果单元格[1]:行 += [((x + i*l, y + j*l + l), (x + i*l + l, y + j*l + l))]对于线中线:pygame.draw.line(冲浪,颜色,*线,宽度)pygame.init()窗口 = pygame.display.set_mode((400, 400))时钟 = pygame.time.Clock()迷宫 = 迷宫()player_rect = pygame.Rect(190, 190, 20, 20)运行 = 真运行时:时钟滴答(100)对于 pygame.event.get() 中的事件:如果 event.type == pygame.QUIT:运行 = 错误迷宫位置 = 20, 20单元格大小 = 40i0 = (player_rect.left - maze_pos[0])//cell_sizei1 = (player_rect.right - maze_pos[0])//cell_sizej0 = (player_rect.top - maze_pos[1])//cell_sizej1 = (player_rect.bottom - maze_pos[1])//cell_size键 = pygame.key.get_pressed()如果键[pygame.K_LEFT]:new_rect = player_rect.move(-3, 0)ni = (new_rect.left - maze_pos[0])//cell_size如果 i0 == ni 或不 (maze.wall_left(i0, j0) or maze.wall_left(i0, j1) or (j0 != j1 and maze.wall_bottom(ni, j0))):player_rect = new_rect如果键[pygame.K_RIGHT]:new_rect = player_rect.move(3, 0)ni = (new_rect.right - maze_pos[0])//cell_size如果 i1 == ni 或不 (maze.wall_right(i1, j0) or maze.wall_right(i1, j1) or (j0 != j1 and maze.wall_bottom(ni, j0))):player_rect = new_rect键 = pygame.key.get_pressed()如果键[pygame.K_UP]:new_rect = player_rect.move(0, -3)nj = (new_rect.top - maze_pos[1])//cell_size如果 j0 == nj 或不 (maze.wall_top(i0, j0) or maze.wall_top(i1, j0) or (i0 != i1 and maze.wall_right(i0, nj))):player_rect = new_rect如果键[pygame.K_DOWN]:new_rect = player_rect.move(0, 3)nj = (new_rect.bottom - maze_pos[1])//cell_size如果 j1 == nj 或不(maze.wall_bottom(i0, j1) or maze.wall_bottom(i1, j1) or (i0 != i1 and maze.wall_right(i0, nj))):player_rect = new_rectwindow.fill(0)绘制迷宫(窗口,迷宫,20, 20, cell_size, (196, 196, 196), 3)pygame.draw.circle(window, (255, 255, 0), player_rect.center, player_rect.width//2)pygame.display.flip()pygame.quit()出口()

I have a maze organized in a grid. Each cell of the grid stores the information about the walls to its right and bottom neighboring cell. The player is an object of a certain size whose bounding box is known. I want to move the player smoothly through the maze with the walls preventing them from going through.

Minimal and reproducible example:

import pygame, random

class Maze:
    def __init__(self, rows = 9, columns = 9):
        self.size = (columns, rows)
        self.walls = [[[True, True] for _ in range(self.size[1])] for __ in range(self.size[0])]
        visited = [[False for _ in range(self.size[1])] for __ in range(self.size[0])]
        i, j = (self.size[0]+1) // 2, (self.size[1]+1) // 2
        visited[i][j] = True
        stack = [(i, j)]
        while stack:
            current = stack.pop()
            i, j = current
            nl = [n for n in [(i-1, j), (i+1, j), (i, j-1), (i, j+1)] 
                  if 0 <= n[0] < self.size[0] and 0 <= n[1] < self.size[1] and not visited[n[0]][n[1]]]
            if nl:
                stack.insert(0, current)
                next = random.choice(nl)
                self.walls[min(next[0], current[0])][min(next[1], current[1])][abs(next[1]-current[1])] = False
                visited[next[0]][next[1]] = True
                stack.insert(0, next)

def draw_maze(surf, maze, x, y, l, color, width):
    lines = [((x, y), (x + l * len(maze.walls), y)), ((x, y), (x, y + l * len(maze.walls[0])))] 
    for i, row in enumerate(maze.walls):
        for j, cell in enumerate(row):
            if cell[0]: lines += [((x + i*l + l, y + j*l), (x + i*l + l, y + j*l + l))]
            if cell[1]: lines += [((x + i*l, y + j*l + l), (x + i*l + l, y + j*l + l))]
    for line in lines:
        pygame.draw.line(surf, color, *line, width)

pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()

maze = Maze()
player_rect = pygame.Rect(190, 190, 20, 20)

run = True
while run:
    clock.tick(100)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    keys = pygame.key.get_pressed()
    player_rect.x += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * 3
    player_rect.y += (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * 3

    window.fill(0)
    draw_maze(window, maze, 20, 20, 40, (196, 196, 196), 3)
    pygame.draw.circle(window, (255, 255, 0), player_rect.center, player_rect.width//2)
    pygame.display.flip()

pygame.quit()
exit()

解决方案

Implement simple logic that tests if there is a wall in the player's path when the player moves. Discard the movement when a collision with a wall is detected.

Add methods to the Maze class that check for a wall between a cell and its neighboring cell:

class Maze:
    # [...]

    def wall_left(self, i, j):
        return i < 1 or self.walls[i-1][j][0]
    def wall_right(self, i, j):
        return i >= self.size[0] or self.walls[i][j][0]
    def wall_top(self, i, j):
        return j < 1 or self.walls[i][j-1][1]
    def wall_bottom(self, i, j):
        return j >= self.size[0] or self.walls[i][j][1]

Calculate the rows and columns of the corner points of the player's bounding box.

i0 = (player_rect.left - maze_pos[0]) // cell_size 
i1 = (player_rect.right - maze_pos[0]) // cell_size
j0 = (player_rect.top - maze_pos[1]) // cell_size  
j1 = (player_rect.bottom - maze_pos[1]) // cell_size  

As the player moves, test to see if the player is entering a new cell. Use the new methods in the Maze class to test whether there is a wall in the player's path. Skip the movement if the path is blocked by a wall:

keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
    new_rect = player_rect.move(-3, 0)
    ni = (new_rect.left - maze_pos[0]) // cell_size
    if i0 == ni or not (maze.wall_left(i0, j0) or maze.wall_left(i0, j1) or (j0 != j1 and maze.wall_bottom(ni, j0))):
        player_rect = new_rect
if keys[pygame.K_RIGHT]:
    new_rect = player_rect.move(3, 0)
    ni = (new_rect.right - maze_pos[0]) // cell_size
    if i1 == ni or not (maze.wall_right(i1, j0) or maze.wall_right(i1, j1) or (j0 != j1 and maze.wall_bottom(ni, j0))):
        player_rect = new_rect
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
    new_rect = player_rect.move(0, -3)
    nj = (new_rect.top - maze_pos[1]) // cell_size
    if j0 == nj or not (maze.wall_top(i0, j0) or maze.wall_top(i1, j0) or (i0 != i1 and maze.wall_right(i0, nj))):
        player_rect = new_rect
if keys[pygame.K_DOWN]:
    new_rect = player_rect.move(0, 3)
    nj = (new_rect.bottom - maze_pos[1]) // cell_size
    if j1 == nj or not (maze.wall_bottom(i0, j1) or maze.wall_bottom(i1, j1) or (i0 != i1 and maze.wall_right(i0, nj))):
        player_rect = new_rect

See also Maze collision detection


Minimal example:

import pygame, random

class Maze:
    def __init__(self, rows = 9, columns = 9):
        self.size = (columns, rows)
        self.walls = [[[True, True] for _ in range(self.size[1])] for __ in range(self.size[0])]
        visited = [[False for _ in range(self.size[1])] for __ in range(self.size[0])]
        i, j = (self.size[0]+1) // 2, (self.size[1]+1) // 2
        visited[i][j] = True
        stack = [(i, j)]
        while stack:
            current = stack.pop()
            i, j = current
            nl = [n for n in [(i-1, j), (i+1, j), (i, j-1), (i, j+1)] 
                  if 0 <= n[0] < self.size[0] and 0 <= n[1] < self.size[1] and not visited[n[0]][n[1]]]
            if nl:
                stack.insert(0, current)
                next = random.choice(nl)
                self.walls[min(next[0], current[0])][min(next[1], current[1])][abs(next[1]-current[1])] = False
                visited[next[0]][next[1]] = True
                stack.insert(0, next)

    def wall_left(self, i, j):
        return i < 1 or self.walls[i-1][j][0]
    def wall_right(self, i, j):
        return i >= self.size[0] or self.walls[i][j][0]
    def wall_top(self, i, j):
        return j < 1 or self.walls[i][j-1][1]
    def wall_bottom(self, i, j):
        return j >= self.size[0] or self.walls[i][j][1]

def draw_maze(surf, maze, x, y, l, color, width):
    lines = [((x, y), (x + l * len(maze.walls), y)), ((x, y), (x, y + l * len(maze.walls[0])))] 
    for i, row in enumerate(maze.walls):
        for j, cell in enumerate(row):
            if cell[0]: lines += [((x + i*l + l, y + j*l), (x + i*l + l, y + j*l + l))]
            if cell[1]: lines += [((x + i*l, y + j*l + l), (x + i*l + l, y + j*l + l))]
    for line in lines:
        pygame.draw.line(surf, color, *line, width)

pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()

maze = Maze()
player_rect = pygame.Rect(190, 190, 20, 20)

run = True
while run:
    clock.tick(100)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    maze_pos = 20, 20
    cell_size = 40
    i0 = (player_rect.left - maze_pos[0]) // cell_size 
    i1 = (player_rect.right - maze_pos[0]) // cell_size
    j0 = (player_rect.top - maze_pos[1]) // cell_size  
    j1 = (player_rect.bottom - maze_pos[1]) // cell_size  

    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        new_rect = player_rect.move(-3, 0)
        ni = (new_rect.left - maze_pos[0]) // cell_size
        if i0 == ni or not (maze.wall_left(i0, j0) or maze.wall_left(i0, j1) or (j0 != j1 and maze.wall_bottom(ni, j0))):
            player_rect = new_rect
    if keys[pygame.K_RIGHT]:
        new_rect = player_rect.move(3, 0)
        ni = (new_rect.right - maze_pos[0]) // cell_size
        if i1 == ni or not (maze.wall_right(i1, j0) or maze.wall_right(i1, j1) or (j0 != j1 and maze.wall_bottom(ni, j0))):
            player_rect = new_rect
    keys = pygame.key.get_pressed()
    if keys[pygame.K_UP]:
        new_rect = player_rect.move(0, -3)
        nj = (new_rect.top - maze_pos[1]) // cell_size
        if j0 == nj or not (maze.wall_top(i0, j0) or maze.wall_top(i1, j0) or (i0 != i1 and maze.wall_right(i0, nj))):
            player_rect = new_rect
    if keys[pygame.K_DOWN]:
        new_rect = player_rect.move(0, 3)
        nj = (new_rect.bottom - maze_pos[1]) // cell_size
        if j1 == nj or not (maze.wall_bottom(i0, j1) or maze.wall_bottom(i1, j1) or (i0 != i1 and maze.wall_right(i0, nj))):
            player_rect = new_rect

    window.fill(0)
    draw_maze(window, maze, 20, 20, cell_size, (196, 196, 196), 3)
    pygame.draw.circle(window, (255, 255, 0), player_rect.center, player_rect.width//2)
    pygame.display.flip()

pygame.quit()
exit()

这篇关于如何防止玩家在 pygame 的迷宫中穿过墙壁?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆