Pygame 使用时钟的延迟问题

Pygame Latency Issue using clock

我用 pygame 制作了一个贪吃蛇游戏,运行良好。但是,有时它对用户输入的响应不是很好。我正在使用时钟和延迟来设置蛇移动的速度。

移动代码:

pygame.time.delay(1)
clock.tick(7)
player.move()
render_screen()

渲染屏幕:

screen.fill((0, 0, 0))
draw_grid()
player.draw()
food.draw()
screen.fill((0, 0, 0), (0, 513, 512, 50))
start.draw()
screen.blit(comic_font.render('Score: ' + str(score), False, (255, 100, 0)), (10, size + 5))
pygame.display.update()

完整代码:

import pygame
import random

pygame.init()


class Snake:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.speed_x = 1
        self.speed_y = 0
        segments = []
        for a in range(1, 4):
            segments.append(Segment(self.x - a, self.y))
        self.segments = segments

    def move(self):
        global score, game_mode
        # handle key inputs
        keys = pygame.key.get_pressed()
        for key in keys:
            if self.speed_x == 0:
                if keys[pygame.K_a]:
                    self.speed_x = -1
                    self.speed_y = 0
                if keys[pygame.K_d]:
                    self.speed_x = 1
                    self.speed_y = 0
            elif self.speed_y == 0:
                if keys[pygame.K_w]:
                    self.speed_x = 0
                    self.speed_y = -1
                if keys[pygame.K_s]:
                    self.speed_x = 0
                    self.speed_y = 1

        # check for wall collisions
        if self.x + self.speed_x < 0 or self.x + self.speed_x > rows - 1 or self.y + self.speed_y > rows - 1 or \
                self.y + self.speed_y < 0:
            game_mode = "end"
            start.text = "RETRY"
            return None

        # moves snake
        self.segments.insert(0, Segment(self.x, self.y))
        self.x += self.speed_x
        self.y += self.speed_y

        # checks for self collisions
        for segment in self.segments:
            if self.x == segment.x and self.y == segment.y and self.segments.index(segment)!=len(self.segments)-1:
                game_mode = "end"
                start.text = "RETRY"
                break

        # checks for eating food
        if self.x == food.x and self.y == food.y:
            food.x = random.randrange(0, 16)
            food.y = random.randrange(0, 16)
            score += 1
        else:
            self.segments.pop()

    def draw(self):
        for segment in self.segments:
            segment.draw()
        pygame.draw.rect(screen, (255, 0, 0), (self.x * size / rows, self.y * size / rows, size / rows, size / rows))


class Segment:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def draw(self):
        pygame.draw.rect(screen, (0, 255 - player.segments.index(self), 0),
                         (self.x * size / rows, self.y * size / rows, size / rows, size / rows))


class Food:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def draw(self):
        pygame.draw.rect(screen, (255, 255, 0), (self.x * size / rows, self.y * size / rows, size / rows, size / rows))


class button:
    def __init__(self, x, y, r, g, b, text, font, width, height):
        self.x = x
        self.y = y
        self.r = r
        self.b = b
        self.g = g
        self.text = text
        self.font = font
        self.width = width
        self.height = height

    def draw(self):
        pygame.draw.rect(screen, (self.r, self.g, self.b), (self.x, self.y, self.width, self.height))
        screen.blit(self.font.render(self.text, False, (0, 100, 0)), (self.x + 10, self.y))

    def mouse_over(self, pos):
        if self.x < pos[0] < self.x + self.width and self.y < pos[1] < self.y + self.height:
            return True


def draw_grid():
    margin = size / rows
    x = 0
    y = 0
    for line in range(rows):
        x = x + margin
        y = y + margin

        pygame.draw.line(screen, (255, 255, 255), (x, 0), (x, size))
        pygame.draw.line(screen, (255, 255, 255), (0, y), (size, y))


def render_screen():
    screen.fill((0, 0, 0))
    draw_grid()
    player.draw()
    food.draw()
    screen.fill((0, 0, 0), (0, 513, 512, 50))
    start.draw()
    screen.blit(comic_font.render('Score: ' + str(score), False, (255, 100, 0)), (10, size + 5))
    pygame.display.update()


size = 512
rows = 16

screen = pygame.display.set_mode((size, size + 50))
pygame.display.set_caption("Snake")

comic_font = pygame.font.SysFont("Comic Sans MS", 30)

clock = pygame.time.Clock()

running = True
game_mode = "wait"

player = Snake(8, 8)
food = Food(random.randrange(0, 16), random.randrange(0, 16))
start = button(size - 155, size + 5, 0, 255, 0, "PLAY", comic_font, 150, 40)

score = 0

render_screen()

while running:
    for event in pygame.event.get():
        pos = pygame.mouse.get_pos()
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            if start.mouse_over(pos):
                if game_mode == "wait":
                    game_mode = "play"
                    start.text = "PAUSE"
                elif game_mode == "play":
                    game_mode = "wait"
                    start.text = "RESUME"
                elif game_mode == "end":
                    game_mode = "play"
                    start.text = "PAUSE"
                    score = 0
                    running = True
                    game_mode = "wait"
                    player = Snake(8, 8)
                    food = Food(random.randrange(0, 16), random.randrange(0, 16))
                render_screen()
    if game_mode == "play":
        pygame.time.delay(1)
        clock.tick(7)
        player.move()
        render_screen()

上面是重现问题的完整代码。

稍微试验了一下,好像pygame.time.delay(1)越小,延迟越小。

我认为用户在抽动之间只能读取输入,因此他们必须在现场准确输入。

我想也许这就是为什么当延迟较小时输入不落后的原因,因为延迟会影响每个输入之间的时长。

有谁知道为什么游戏在某些时候不能很好地接收输入?

pygame.key.get_pressed() returns 一个列表,包含所有键盘按钮的状态。遍历此列表没有意义,因为您只想评估键的当前状态 was d.

根据按下的键设置速度:

class Snake:
    # [...]

    def move(self):
        # [...]
        
        # handle key inputs
        keys = pygame.key.get_pressed()
        if self.speed_x == 0:
            if keys[pygame.K_a]:
                self.speed_x, self.speed_y = -1, 0
            elif keys[pygame.K_d]:
                self.speed_x, self.speed_y = 1, 0
        elif self.speed_y == 0:
            if keys[pygame.K_w]:
                self.speed_x, self.speed_y = 0, -1
            elif keys[pygame.K_s]:
                self.speed_x, self.speed_y = 0, 1

        # [...]

pygame.time.Clock.tick 延迟以使游戏 运行 慢于给定的每秒滴答数。 pygame.key.get_pressed() 返回的状态在处理事件时进行评估 (pygame.event.get())。
延迟游戏,等事件处理完毕,蛇被移动,显示更新:

while running:
    for event in pygame.event.get():
        # [...]

    if game_mode == "play":
        player.move()
        render_screen()
        clock.tick(7) # <---