按住 window 时玩家消失

player dissapear when the window is held

我正在尝试进行基于帧的移动。但是我注意到,当 window 被按住时,fps 会暂时增加并且玩家会消失。在我的系统中,dt 的值介于 1.06 和 0.96 之间。一切似乎都正常,除非 window 被按住。
This video shows the problem。第 124 和 125 行解决了问题,但正如评论所说,我不知道这是否是解决问题的正确方法。
该问题似乎只出现在 windows 10 个系统上。

import sys
import pygame
from pygame.locals import *
vec = pygame.math.Vector2

pygame.init()

fps = 60
fpsClock = pygame.time.Clock()

width, height = 1024, 768
TILESIZE = 32
screen = pygame.display.set_mode((width, height))

class Player(pygame.sprite.Sprite):
    def __init__(self,x,y):
        super().__init__()
        self.image = pygame.Surface((TILESIZE, TILESIZE))
        self.image.fill('green')
        self.rect = self.image.get_rect(topleft=(x,y))
        self.pos = vec(self.rect.topleft)
        self.speed = .8
        self.direction = vec(0,0)
        self.gravity = .8
        self.jump_height = -15
        self.friction = -.12
        self.velocity = vec(0,0)
        self.acceleration = vec(0,self.gravity)

    def update(self):
        keys = pygame.key.get_pressed()
        self.acceleration.x = 0
        if keys[K_RIGHT]:
            self.acceleration.x = self.speed 
        elif keys[K_LEFT]:
            self.acceleration.x = -self.speed
        if keys[K_UP]:
            self.velocity.y = self.jump_height        
    
class Obstacle(pygame.sprite.Sprite):
    def __init__(self,pos,width,height,color):
        super().__init__()
        self.image = pygame.Surface((width,height))
        self.image.fill(color)
        self.rect = self.image.get_rect(topleft=pos)


tiles_map = [
    "................................",
    "................................",
    "................................",
    "................................",
    "................................",
    "................................",
    "................................",
    "................................",
    "................................",
    "................................",
    "................................",
    "................................",
    "................................",
    "................................",
    "................................",
    "................................",
    "................................",
    "................................",
    "................................",
    "..P.............................",
    "................................",
    "................................",
    "11111111111111111111111111111111",
    "11111111111111111111111111111111"
]

class Game:
    def __init__(self):
        self.player_sprite = pygame.sprite.GroupSingle()
        self.obstacles =  pygame.sprite.Group()
        for row,line in enumerate(tiles_map):
            for col, char in enumerate(line):
                if char == "1":
                    self.obstacles.add(Obstacle((col*TILESIZE,row*TILESIZE),TILESIZE,TILESIZE,'red'))
                elif char == "P":
                    self.player_sprite.add(Player(col*TILESIZE,row*TILESIZE))
    
    def horizontal_movement(self, dt):
        player = self.player_sprite.sprite
        # equations of motion
        player.acceleration.x += player.velocity.x * player.friction
        player.velocity.x += player.acceleration.x * dt
        player.pos.x += player.velocity.x * dt + 0.5 * player.acceleration.x * dt **2
        player.rect.x = round(player.pos.x)
    
    def vertical_movement(self, dt):
        player = self.player_sprite.sprite
        # equations of motion
        player.velocity.y += player.acceleration.y * dt
        player.pos.y += player.velocity.y * dt + (player.acceleration.y * .5) * dt**2
        player.rect.y = round(player.pos.y)

        for obstacle in self.obstacles.sprites():
            if obstacle.rect.colliderect(player.rect):
                if player.velocity.y > 0: # falling
                    player.rect.bottom = obstacle.rect.top
                    player.pos.y = player.rect.y
                    player.velocity.y = 0
        

    def update(self, dt):
        self.player_sprite.update()
        self.player_sprite.draw(screen)
        self.obstacles.draw(screen)
        self.horizontal_movement(dt)
        self.vertical_movement(dt)

game = Game()
while True:
    dt = fpsClock.tick(60) /1000 * fps # normalize
    print(dt)
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()    
    # if dt > 1.2: # it solves the problem but i don't know if this is the correct way to fix it
    #     dt = 1.2
    screen.fill('white')    
    game.update(dt)
    pygame.display.update()
    
    

pygame.time.Clock.tick returns how many milliseconds have passed since the previous call. The problem with your code is that the first time returned is very large. This is the time from the creation of the pygame.time.Clock object to the first call of tickgame = Game()需要很长时间。

在应用程序循环之前创建 pygame.time.Clock 以解决问题:

game = Game()
fpsClock = pygame.time.Clock()
while True:
    dt = fpsClock.tick(fps) / 1000 * fps
   
    # [...]

如果 2 帧之间的时间太长 dt 太大,加速度太大,您的算法就会崩溃。如果只有一个“慢”帧,重力会变得太大,玩家会无处可去。解决这个问题的唯一方法是限制 dt:

while True:
    dt = fpsClock.tick(60) / 1000 * fps
    dt = min(dt, 1.5)

    # [...]