Python 3.x 为什么这个简单的pygame程序落后?

Python 3.x 为什么这个简单的pygame程序落后?,python-3.x,pygame,Python 3.x,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(&quo

所以,我学习编程很短时间,决定在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()
导入pygame
pygame.init()
#窗口
窗口=(1280720)
中心=(窗口[0]//2,窗口[1]//2)
screen=pygame.display.set_模式(窗口)
pygame.display.set_标题(“蛇”)
#颜色
颜色\浅\灰色=(200200200)
COLOR\u DARK\u GREY=pygame.COLOR('gray12'))
#游戏循环
游戏循环=正确
game\u clock=pygame.time.clock()
#创造形象
def img(名称):
img_path=“./assets/natanael.lucena_”+name+.png”
返回pygame.image.load(img_路径).convert_alpha()
#设置对象坐标
def set_obj_坐标(obj,x,y):
对象x=x
对象y=y
#检查播放器按键
def检查播放器按键(b):
全球蛇行方向
如果event.key==pygame.K_w或event.key==pygame.K_s或event.key==pygame.K_a或event.key==pygame.K_d:
snake_方向[event.key]=b
#检查游戏中的关键事件
def event_conditional():
全局博弈循环
如果event.type==pygame.QUIT:
博弈循环=错误
elif event.type==pygame.KEYDOWN:
检查\u播放器\u键(正确)
elif event.type==pygame.KEYUP:
检查\u播放器\u键(错误)
#检查蛇是否相撞,游戏是否结束
def game_over():
如果snake.y<0或snake.y>720或snake.x<0或snake。x>1280:
返回真值
#蛇
snake\u img=img(“snake”)
snake=snake\u img.get\u rect()
move_keys=[pygame.K_w,pygame.K_d,pygame.K_s,pygame.K_a]
snake_方向={k:move_键中的k为False}
snake_得分=0
蛇级别=10
设置对象坐标(蛇,中心[0],中心[1])
#苹果
苹果_img=img(“苹果”)
apple=apple\u img.get\u rect()
吃了苹果=错
设置对象坐标(苹果,40,40)
#主游戏循环
在游戏循环中:
对于pygame.event.get()中的事件:
事件_条件()
#分数\文本=文本\渲染(蛇分数)
如果不是游戏结束():
对于范围(4)中的i:
如果我是%2:
coord_aux=“x”
其他:
coord_aux=“y”
如果我是%3:
op=“+=”
其他:
op=“-=”
如果方向[移动键[i]]:
执行官(“蛇”+coord_aux+op+“蛇级别”)
#上述for循环相当于:
#如果方向[移动键[0]]:
#snake.y-=蛇级别
#如果蛇形方向[移动按键[1]]:
#snake.x+=snake_等级
#如果方向[移动键[2]]:
#snake.y+=蛇级别
#如果蛇形方向[移动按键[3]]:
#snake.x-=snake_等级
屏幕填充(颜色为深灰色)
屏幕。blit(snake\u img,snake)
screen.blit(苹果公司)
#更新屏幕
pygame.display.flip()
游戏时钟滴答(60)
pygame.quit()
如果有人能告诉我问题的原因,我真的很感激


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

很可能是线路瓶颈

exec(“snake.+coord\u aux+op+“snake\u vel”)
exec
必须解析和解释参数中的文本

这段代码很容易改进

如果不是游戏结束():
对于范围(4)中的i:
如果方向[移动键[i]]:
如果i%3其他-1,则符号=1
如果我是%2:
snake.x+=符号*snake\u级别
其他:
snake.y+=符号*snake\u级别
由于
snake
是一个对象,您甚至可以执行以下操作:

如果不是游戏结束():
对于范围(4)中的i:
如果方向[移动键[i]]:
如果i%3其他-1,则符号=1
蛇[(i+1)%2]+=符号*蛇级别

然而:

键盘事件(请参阅模块)仅在按键状态更改时发生一次。每次按键时,
KEYDOWN
事件发生一次
KEYUP
在每次释放钥匙时发生一次。将键盘事件用于单个操作或逐步移动

返回包含每个键状态的列表。如果按下某个键,则该键的状态为
True
,否则为
False
。用于评估按钮的当前状态并获得连续移动

使用
pygame.key.get_pressed()
进行平稳的连续移动:

#主游戏循环
在游戏循环中:
对于pygame.event.get()中的事件:
事件_条件()
#分数\文本=文本\渲染(蛇分数)
如果不是游戏结束():
keys=pygame.key.get_pressed()
snake.x+=(keys[pygame.K_d]-keys[pygame.K_a])*snake等级
snake.y+=(key[pygame.K_-s]-key[pygame.K_-w])*snake\u-vel
# [...]

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

您应该执行以下操作:

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

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

  • 使用一个

你也可以为游戏中需要不同计时方法的部分使用不同的线程(例如,你的游戏逻辑要求固定的30或60 FPS,你的绘图代码希望尽可能快地运行),但这对于你的小游戏来说是多余的

所以
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()