在 pygame 玩家与墙壁碰撞时拒绝移动

Deny movement in pygame when player would collide with a wall

我在 pygame 中遇到了碰撞问题。具体来说,我有一个播放器和一列墙,如果它们发生碰撞,我应该阻止向那个方向的任何移动。

我尝试了很多指南,但我自己似乎无法让它发挥作用。

import pygame
pygame.init()

win = pygame.display.set_mode((800,600))
pygame.display.set_caption("Game")

playerX = 380 #Player X coordinate
playerY = 380 #Player Y coordinate
playerXVel = 10 #Horizontal Velocity
playerYVel = 10 #Vertical Velocity
overworld = (248, 192, 117)

run = True

while run: #The game starts running
    win.fill(overworld)
    pygame.time.delay(30)

    for event in pygame.event.get(): #You can stop the game now too
        if event.type == pygame.QUIT:
            run = False

    class Player: #This is you
        def __init__(self):
            self.rect = pygame.Rect(playerX,playerY,50,50)
    player = Player()

    class Wall: #The walls
        def __init__(self, pos):
            walls.append(self)
            self.rect = pygame.Rect(pos[0], pos[1], 50, 50)
    walls = []
    
    keys = pygame.key.get_pressed()  #To retain the feel of retro video games, I have made it impossible to walk diagonally
    if keys[pygame.K_w] and not keys[pygame.K_a] and not keys[pygame.K_d]:
        playerY -= playerYVel
    if keys[pygame.K_a] and not keys[pygame.K_w] and not keys[pygame.K_s]:
        playerX -= playerXVel
    if keys[pygame.K_s] and not keys[pygame.K_a] and not keys[pygame.K_d]:
        playerY += playerYVel
    if keys[pygame.K_d] and not keys[pygame.K_s] and not keys[pygame.K_w]:
        playerX += playerXVel

    #I copied this section of code
    #Credit: https://www.pygame.org/project-Rect+Collision+Response-1061-.html
    level = [
        "WWWWWWWWWWWWWWWW",
        "W              W",
        "W              W",
        "W              W",
        "W              W",
        "W              W",
        "W              W",
        "W              W",
        "W              W",
        "W              W",
        "W              W",
        "WWWWWWWWWWWWWWWW",
    ]
    x = y = 0
    for row in level:
        for col in row:
            if col == "W":
                Wall((x, y)) 
            x += 50
        y += 50
        x = 0

    #Drawing every rectangle in :3
    pygame.draw.rect(win, (0, 255, 0), player.rect)
    for wall in walls:
        pygame.draw.rect(win, (143, 41, 3), wall.rect)

    pygame.display.update()
pygame.quit()

到目前为止一切顺利。我有墙,我有一个玩家,那个玩家可以移动。但是,玩家可以穿过墙壁。

我想放入一段代码,以防止在玩家与墙壁碰撞时添加或删除速度。这是我尝试向上行走的方法,但它只是让我无法完全向上行走

        for allwalls in walls:
            if not player.rect.colliderect(allwalls):
                playerY -= playerYVel

谁能告诉我我在做什么wrong/what我应该输入代码而不是防止玩家穿墙?

在应用程序循环之前创建一次对象。您根本不需要变量 playerXplayerY。请改用 player.rect.xplayer.rect.y

在移动之前存储玩家的位置。如果检测到碰撞,恢复玩家位置:

oldPlyerX, oldPlyerY = player.rect.topleft          # store player position

keys = pygame.key.get_pressed()
if keys[pygame.K_w] and not keys[pygame.K_a] and not keys[pygame.K_d]:
    player.rect.y -= playerYVel
if keys[pygame.K_a] and not keys[pygame.K_w] and not keys[pygame.K_s]:
    player.rect.x -= playerXVel
if keys[pygame.K_s] and not keys[pygame.K_a] and not keys[pygame.K_d]:
    player.rect.y += playerYVel
if keys[pygame.K_d] and not keys[pygame.K_s] and not keys[pygame.K_w]:
    player.rect.x += playerXVel

for allwalls in walls:
    if player.rect.colliderect(allwalls):
        player.rect.topleft = oldPlyerX, oldPlyerY # restore player position

完整示例:

import pygame
pygame.init()

win = pygame.display.set_mode((800,600))
pygame.display.set_caption("Game")

playerXVel = 10 #Horizontal Velocity
playerYVel = 10 #Vertical Velocity
overworld = (248, 192, 117)

class Player: #This is you
    def __init__(self):
        self.rect = pygame.Rect(380,380,50,50)
player = Player()

class Wall: #The walls
    def __init__(self, pos):
        walls.append(self)
        self.rect = pygame.Rect(pos[0], pos[1], 50, 50)
walls = []

#I copied this section of code
#Credit: https://www.pygame.org/project-Rect+Collision+Response-1061-.html
level = [
    "WWWWWWWWWWWWWWWW",
    "W              W",
    "W              W",
    "W              W",
    "W              W",
    "W              W",
    "W              W",
    "W              W",
    "W              W",
    "W              W",
    "W              W",
    "WWWWWWWWWWWWWWWW",
]
x = y = 0
for row in level:
    for col in row:
        if col == "W":
            Wall((x, y)) 
        x += 50
    y += 50
    x = 0

run = True

while run: #The game starts running
    win.fill(overworld)
    pygame.time.delay(30)

    for event in pygame.event.get(): #You can stop the game now too
        if event.type == pygame.QUIT:
            run = False

    oldPlyerX, oldPlyerY = player.rect.topleft
    keys = pygame.key.get_pressed()  #To retain the feel of retro video games, I have made it impossible to walk diagonally
    if keys[pygame.K_w] and not keys[pygame.K_a] and not keys[pygame.K_d]:
        player.rect.y -= playerYVel
    if keys[pygame.K_a] and not keys[pygame.K_w] and not keys[pygame.K_s]:
        player.rect.x -= playerXVel
    if keys[pygame.K_s] and not keys[pygame.K_a] and not keys[pygame.K_d]:
        player.rect.y += playerYVel
    if keys[pygame.K_d] and not keys[pygame.K_s] and not keys[pygame.K_w]:
        player.rect.x += playerXVel

    for allwalls in walls:
        if player.rect.colliderect(allwalls):
            player.rect.topleft = oldPlyerX, oldPlyerY

    #Drawing every rectangle in :3
    pygame.draw.rect(win, (0, 255, 0), player.rect)
    for wall in walls:
        pygame.draw.rect(win, (143, 41, 3), wall.rect)

    pygame.display.update()
pygame.quit()