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("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 2/sdl 2 之后,您无法再使用directx
视频驱动程序并启用 vsync。
您应该执行以下操作:
跟踪移动游戏对象的亚像素坐标。A
Rect
只能在其x
和y
属性中存储整数值,因此您需要另一个变量来存储它。我通常使用 aVector2
,因为它易于使用,而且性能损失通常无关紧要。使用准确的时钟。Pygame 的时钟对象只使用毫秒,这对于真正平滑的移动来说不够精确。如果你在 Windows 上,通常最好的计时方法是
GetSystemTimePreciseAsFileTime
函数。使用增量计时。
您还可以为需要不同计时方法的游戏部分使用不同的线程(例如,您的游戏逻辑需要固定的 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()
推荐阅读
- ballerina - Ballerina github4 api 中的“存储库”类型错误中不存在字段“许可证”
- xslt - 使用 xslt 创建 pdf 时,是否可以有一个书签在其所有子部分中保持突出显示
- android - HorizontalScrollView -> LinearLayout -> TextView — 文本更改后滚动条大小不重置
- python-3.x - Pynetdicom3 传输语法
- javascript - 如何进行平滑的嵌套过渡
- postgresql - 为什么我的超级用户无法在 psql 中进行身份验证?
- php - PHP if/else 同时执行
- sql-server - 可以将 mdf 文件存储在不同的驱动器(和 ldf 文件)上吗?
- ios - 在 UiScrollView 中的 UIView 中的 UITextField 中无法识别触摸事件
- java - Java DefaultExecutor 在 Windows 7 上的长路径上失败错误 = 267