Pygame 中简单 2D 平台游戏的碰撞检测问题

Issue with Collision Detection in Pygame for simple 2D Platformer

这是我的第一个 post 所以请告诉我是否需要更改任何内容。

我正在尝试创建一个简单的测试 2D 平台游戏,这是我在没有教程的情况下进行的第一个 pygame 项目。我遇到的问题是由于这个 can_jump 变量引起的。我正在使用此变量来阻止玩家在不在平台或屏幕底部时跳跃。我曾尝试过其他方法,但这就是我的结局。我觉得我已经很接近了。

目前的问题似乎是变量 self.can_jump1 在平台循环中不断地在 TrueFalse 之间交换(恰好在 3 False 秒每 True 我注意到)站在平台上时,我将其隔离到 collision_check() 中的评论部分。我不知道为什么会这样,据我所知,其余代码都按我的意愿工作。

如果需要,我很乐意提供额外的 information/clarification。

这是我的代码:

import pygame, sys, random

#---Classes----------------------------------------#
class Block(pygame.sprite.Sprite): #inherited by rest of classes
    def __init__(self,path,x_pos,y_pos,size_x,size_y):
        super().__init__()
        self.image = pygame.transform.scale(pygame.image.load(path).convert_alpha(),(size_x,size_y))
        self.rect = self.image.get_rect(center = (x_pos,y_pos))

class PlatformRect(pygame.sprite.Sprite):
    def __init__(self,x_pos,y_pos,size_x,size_y,colour,players):
        super().__init__()
        self.center_x = x_pos
        self.center_y = y_pos
        self.size_x = size_x
        self.size_y = size_y
        self.colour = colour
        self.players = players
        self.can_jump1 = None

        self.image = pygame.Surface((self.size_x,self.size_y))
        self.image.fill(self.colour)
        self.rect = self.image.get_rect(center = (self.center_x,self.center_y))

    def collision_check(self):
        if pygame.sprite.spritecollide(self,self.players,False):
            collision_paddle = pygame.sprite.spritecollide(self,self.players,False)[0].rect
            if abs(self.rect.top - collision_paddle.bottom) < 10:
                collision_paddle.bottom = self.rect.top
                player.movement_y = 0
                self.can_jump1 = True
        else: #error isolated to here,consistently fluctuates between True and False, not sure why
            self.can_jump1 = False
        print(self.can_jump1) #if standing on platform should only produce True, everywhere else produce False

    def can_jump_check(self):
        return self.can_jump1

    def update(self):
        self.collision_check()


class Player(Block):
    def __init__(self,path,x_pos,y_pos,size_x,size_y,speed_x,acceleration_y):
        super().__init__(path,x_pos,y_pos,size_x,size_y)
        self.size_x = size_x
        self.size_y = size_y
        self.speed_x = speed_x
        self.acceleration_y = acceleration_y
        self.movement_x = 0
        self.movement_y = 0

    def screen_constrain(self):
        if self.rect.bottom >= sresy:
            self.rect.bottom = sresy
        if self.rect.left <= 0:
            self.rect.left = 0
        if self.rect.right >= sresx:
            self.rect.right = sresx

    def update(self):
        if abs(self.movement_y) <= 9:
            self.movement_y += GRAVITY
        self.rect.centery += self.movement_y
        self.rect.centerx += self.movement_x
        self.screen_constrain()

class GameManager:
    def __init__(self,player_group,platform_group):
        self.player_group = player_group
        self.platform_group = platform_group
        self.can_jump = True

    def run_game(self):
        #---drawing---#
        self.player_group.draw(screen)
        self.platform_group.draw(screen)

        #---updating---#
        self.player_group.update()
        self.platform_group.update()

    def game_checking(self):
        #---checking---#
        for sprite_platform in self.platform_group.sprites():
            if not sprite_platform.can_jump_check() == True:
                self.can_jump = False
            else:
                self.can_jump = True
            return self.can_jump




#---Setup------------------------------------------#
#---constants-----#
global GRAVITY
GRAVITY = 0.25

#---Gamevariables-----#
can_jump = True

#---colour---#
bg_colour = (50,50,50)
white_colour = (255,255,255)
black_colour = (0,0,0)

#---res---#
resx = 900
resy = 675
sresx = resx - 50
sresy = resy - 50


#---start window-----#
clock = pygame.time.Clock()

screendisplay = pygame.display.set_mode((resx,resy))
screendisplay.fill(bg_colour)
pygame.display.set_caption("PlatformerGame1 started 09/02/2021")

screen = pygame.Surface((sresx,sresy))
screen.fill(white_colour)

#---startgame-----#
player = Player("assets\pics\TestPlayerFigure1_256512.png",100,100,32,64,10,30)
player_group = pygame.sprite.GroupSingle()
player_group.add(player)

platform1 = PlatformRect(100,550,100,10,black_colour,player_group)
platform_group = pygame.sprite.Group()
platform_group.add(platform1)

game_manager = GameManager(player_group,platform_group)

#---Loop--------------------------------------------#
while True:
    #---events-----#
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                pygame.quit()
                sys.exit()

            if event.key == pygame.K_SPACE:
                if can_jump == True:
                    player.movement_y = 0
                    player.movement_y -= player.acceleration_y * GRAVITY
            if event.key == pygame.K_a:
                player.movement_x -= player.speed_x
            if event.key == pygame.K_d:
                player.movement_x += player.speed_x

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_SPACE:
                if player.movement_y < 0:
                    player.movement_y = 0
            if event.key == pygame.K_a:
                player.movement_x += player.speed_x
            if event.key == pygame.K_d:
                player.movement_x -= player.speed_x

    #---background---#
    screendisplay.blit(screen,(25,25))
    screen.fill(white_colour)

    #---running---#
    game_manager.run_game()
    if not game_manager.game_checking() == True and player.rect.bottom < sresy:
        can_jump = False
    else:
        can_jump = True
    #print(can_jump)

    #---updating-----#
    pygame.display.update()
    clock.tick(60)

当玩家站在平台上时,玩家不会与平台发生碰撞,self.can_jump1设置为False。测试玩家是否平台上,当玩家不与平台发生碰撞时:

self.can_jump1 = False

self.can_jump1 = self.rect.top == self.players.sprites()[0].rect.bottom

方法collision_check:

class PlatformRect(pygame.sprite.Sprite):
    # [...]

    def collision_check(self):
        collide_list = pygame.sprite.spritecollide(self,self.players,False)
        if collide_list: 
            collision_paddle = collide_list[0].rect
            if abs(self.rect.top - collision_paddle.bottom) < 10:
                collision_paddle.bottom = self.rect.top
                player.movement_y = 0
                self.can_jump1 = True
        else:
            self.can_jump1 = self.rect.top == self.players.sprites()[0].rect.bottom

GameManager.game_checking需要检查plyer是否与任何平台发生碰撞:

class GameManager:
    # [...]

    def game_checking(self):
        #---checking---#
        self.can_jump = False
        for sprite_platform in self.platform_group.sprites():
            if sprite_platform.can_jump_check() == True:
                self.can_jump = True
        return self.can_jump

这可以用 any 函数简化:

class PlatformRect(pygame.sprite.Sprite):
    # [...]

    def game_checking(self):
        #---checking---#
        self.can_jump = any(p.can_jump_check() for p in self.platform_group)
        return self.can_jump