问题描述
所以,我一直在学习编程很短的时间,并决定在 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()
编辑:看起来问题只是发生在我身上
解决方法
瓶颈很可能是线路
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
只能在其x
和y
属性中存储整数值,因此您需要另一个变量来存储它。我通常使用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()