微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么这个简单的 pygame 程序滞后?

如何解决为什么这个简单的 pygame 程序滞后?

所以,我一直在学习编程很短的时间,并决定在 pygame 中制作贪吃蛇游戏。然而,在制作程序的基础时,我意识到由玩家控制的矩形(蛇)在移动时每秒都在传送(可能是延迟)。代码如下:

import pygame

pygame.init()

# Window
window = (1280,720)
center = (window[0]//2,window[1]//2)
screen = pygame.display.set_mode(window)
pygame.display.set_caption("Snake")

# Colors
COLOR_LIGHT_GREY = (200,200,200)
COLOR_DARK_GREY = pygame.Color('gray12')

# Game loop
game_loop = True
game_clock = pygame.time.Clock()


# Create image
def img(name):
    img_path = "./assets/natanael.lucena_" + name + ".png"
    return pygame.image.load(img_path).convert_alpha()


# Set object coordinates
def set_obj_coordinates(obj,x,y):
    obj.x = x
    obj.y = y


# Check player key press
def check_player_key(b):
    global snake_direction
    if event.key == pygame.K_w or event.key == pygame.K_s or event.key == pygame.K_a or event.key == pygame.K_d:
        snake_direction[event.key] = b


# Check key events in-game
def event_conditional():
    global game_loop
    if event.type == pygame.QUIT:
        game_loop = False
    elif event.type == pygame.KEYDOWN:
        check_player_key(True)
    elif event.type == pygame.KEYUP:
        check_player_key(False)

# Check if the snake collided and the game is over
def game_over():
    if snake.y < 0 or snake.y > 720 or snake.x < 0 or snake. x > 1280:
        return True


# Snake
snake_img = img("snake")
snake = snake_img.get_rect()
move_keys = [pygame.K_w,pygame.K_d,pygame.K_s,pygame.K_a]
snake_direction = {k: False for k in move_keys}
snake_score = 0
snake_vel = 10
set_obj_coordinates(snake,center[0],center[1])


# Apple
apple_img = img("apple")
apple = apple_img.get_rect()
apple_eaten = False
set_obj_coordinates(apple,40,40)


# Main game loop
while game_loop:
    for event in pygame.event.get():
        event_conditional()
    # score_text = text_render(snake_score)
    if not game_over():
        for i in range(4):
            if i % 2:
                coord_aux = "x "
            else:
                coord_aux = "y "
            if i % 3:
                op = "+= "
            else:
                op = "-= "
            if snake_direction[move_keys[i]]:
                exec("snake." + coord_aux + op + "snake_vel")

        # the for loop above is equivalent to :
        # if snake_direction[move_keys[0]]:
        #    snake.y -= snake_vel
        # if snake_direction[move_keys[1]]:
        #    snake.x += snake_vel
        # if snake_direction[move_keys[2]]:
        #    snake.y += snake_vel
        # if snake_direction[move_keys[3]]:
        #    snake.x -= snake_vel

        screen.fill(COLOR_DARK_GREY)
        screen.blit(snake_img,snake)
        screen.blit(apple_img,apple)

    # Update screen
    pygame.display.flip()
    game_clock.tick(60)

pygame.quit()

Here what's happening with me

如果有人能告诉我问题的原因,我真的很感激。

编辑:看起来问题只是发生在我身上

解决方法

瓶颈很可能是线路

adminlte

exec("snake." + coord_aux + op + "snake_vel") 必须解析和解释参数中的文本。

此代码可以轻松改进

exec

由于 if not game_over(): for i in range(4): if snake_direction[move_keys[i]]: sign = 1 if i % 3 else -1 if i % 2: snake.x += sign * snake_vel else: snake.y += sign * snake_vel 是一个 pygame.Rect 对象,您甚至可以执行以下操作:

snake

然而:

键盘事件(参见 pygame.event 模块)仅在键的状态改变时发生一次。 if not game_over(): for i in range(4): if snake_direction[move_keys[i]]: sign = 1 if i % 3 else -1 snake[(i+1) % 2] += sign * snake_vel 事件在每次按下键时发生一次。 KEYDOWN 每次释放键时出现一次。将键盘事件用于单个操作或逐步移动。

pygame.key.get_pressed() 返回一个包含每个键状态的列表。如果某个键被按下,则该键的状态为 KEYUP,否则为 True。使用 pygame.key.get_pressed() 评估按钮的当前状态并获得连续移动。

使用 False 进行平滑的连续移动:

pygame.key.get_pressed()
,

这是 pygame 的一个常见问题,尤其是在 pygame 2/sdl 2 之后,您无法再使用 directx 视频驱动程序并启用 vsync。

您应该执行以下操作:

  • 跟踪移动游戏对象的子像素坐标。 Rect 只能在其 xy 属性中存储整数值,因此您需要另一个变量来存储它。我通常使用 Vector2,因为它易于使用,而且性能影响通常无关紧要。

  • 使用准确的时钟。 Pygame 的时钟对象只使用毫秒,这对于真正平滑的移动来说不够准确。如果您使用的是 Windows,通常最好的计时方法是 GetSystemTimePreciseAsFileTime 函数。

  • 使用 delta timing

您还可以为需要不同计时方法的游戏部分使用不同的线程(例如,您的游戏逻辑需要固定的 30 或 60 FPS,并且您的绘图代码希望尽可能快地运行),但这对于您的小型游戏。

所以这是我一起编写的一个示例,它可以让您平滑移动(至少这是我通常使用的,因为它对我来说效果很好。请注意,它是特定于 Windows 的):

import pygame

import ctypes.wintypes

pygame.init()


screen = pygame.display.set_mode((1280,720))
center = screen.get_rect().center
pygame.display.set_caption("Snake")


game_loop = True

# https://stackoverflow.com/a/28574340/142637
def utcnow_microseconds():
    system_time = ctypes.wintypes.FILETIME()
    ctypes.windll.kernel32.GetSystemTimePreciseAsFileTime(ctypes.byref(system_time))
    large = (system_time.dwHighDateTime << 32) + system_time.dwLowDateTime
    return large // 10 - 11644473600000000

# Snake
snake_img = pygame.Surface((40,40))
snake_img.fill('white')
snake = snake_img.get_rect()

snake_vel = 10
snake_pos = pygame.Vector2(center[0],center[1])
snake.topleft = snake_pos.x,snake_pos.y

# Apple
apple_img = pygame.Surface((40,40))
apple_img.fill('red')
apple = apple_img.get_rect(topleft=(40,40))


dt = 0
while game_loop:

    t1 = utcnow_microseconds()
    
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            game_loop = False
            
    keys = pygame.key.get_pressed()
    snake_pos.x += (keys[pygame.K_d] - keys[pygame.K_a]) * snake_vel * dt
    snake_pos.y += (keys[pygame.K_s] - keys[pygame.K_w]) * snake_vel * dt
    snake.topleft = snake_pos.x,snake_pos.y

    screen.fill('darkgrey')
    screen.blit(snake_img,snake)
    screen.blit(apple_img,apple)

    pygame.display.flip()

    t2 = utcnow_microseconds()
    dt = (t2 - t1) / 1000. / 1000. * 30

pygame.quit()

Further reading

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。