Mượt mà ở mọi tốc độ khung hình
Thuộc phần Âm thanh và cảm giác chơi trong hành trình Pygame của Coddy. Bài học 19 trên 23.
x += (target_x - x) * 0.1 di chuyển một phần mười quãng đường mỗi khung hình. Ở tốc độ 60 khung hình mỗi giây, đó là 60 bước mỗi giây; trên máy tính chậm chỉ chạy được 30 khung hình, con số này chỉ còn 30 bước, và vòng tròn mất gấp đôi thời gian để đến nơi. Nhấn F để xem: trò chơi chạy ở tốc độ 30 khung hình mỗi giây và mọi thứ chuyển động chậm hơn.
Cách khắc phục là đo thời gian. clock.tick() trả về số mili giây kể từ khung hình trước. Chia cho 1000 sẽ ra dt, độ dài của khung hình tính bằng giây: khoảng 0.017 ở tốc độ 60 khung hình mỗi giây, 0.033 ở tốc độ 30.
dt = 1 / 60 # trước vòng lặp
...
step = min(1, 6 * dt)
x += (target_x - x) * step
...
dt = clock.tick(fps) / 1000Khung hình dài hơn sẽ tạo ra bước di chuyển lớn hơn, nhờ đó vòng tròn di chuyển cùng một quãng đường trong cùng một khoảng thời gian ở mọi tốc độ khung hình. Số 6 thiết lập tốc độ: ở tốc độ 60 khung hình mỗi giây, 6 * dt xấp xỉ 0.1, bằng một phần mười như trước. min(1, ...) ngăn khung hình quá dài khiến vòng tròn di chuyển vượt qua đích.
Điều tương tự cũng áp dụng cho chuyển động thông thường: player_x += 240 * dt tương đương 240 pixel mỗi giây, bất kể tốc độ khung hình. Hầu hết trò chơi nhỏ đều cố định tốc độ bằng tick(60) nên không cần cách này; hãy dùng dt khi tốc độ có thể thay đổi.
Thử thách
Trung bìnhGiữ cho chuyển động giảm tốc mất cùng một khoảng thời gian ở mọi tốc độ khung hình.
- Đặt
dt = 1 / 60trước vòng lặp. - Ở cuối vòng lặp, đặt
dt = clock.tick(fps) / 1000. - Trong cả hai dòng giảm tốc, dùng
step = min(1, 6 * dt)thay cho 0.1:x += (target_x - x) * step.
Nhấn Chơi, nhấp chuột, rồi nhấn F và nhấp chuột: chuyển động lướt mất cùng một khoảng thời gian. Sau đó nhấn Kiểm tra.
Tự làm thử
import pygame
pygame.init()
screen = pygame.display.set_mode((480, 360))
pygame.display.set_caption("Any Frame Rate")
clock = pygame.time.Clock()
font = pygame.font.Font(None, 28)
x, y = 240, 180
target_x, target_y = 240, 180
fps = 60
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
target_x, target_y = event.pos
elif event.type == pygame.KEYDOWN and event.key == pygame.K_f:
fps = 30 if fps == 60 else 60
x += (target_x - x) * 0.1
y += (target_y - y) * 0.1
screen.fill((30, 30, 46))
pygame.draw.circle(screen, (80, 200, 220), (x, y), 12)
label = font.render(f"{fps} FPS (F to change)", True, (240, 240, 240))
screen.blit(label, (10, 10))
pygame.display.flip()
clock.tick(fps)
pygame.quit()
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Âm thanh và cảm giác chơi
4Rung màn hình và chớp sáng khi trúng đòn
Rung màn hìnhChớp sáng khi trúng đònKhựng hình khi trúng đònGiữ hiệu ứng tinh tế5Chuyển động mượt mà
Di chuyển về phía mục tiêuCamera mượt màBật lên khi nhặtMượt mà ở mọi tốc độ khung hìnhTự luyện tập: Playground Pygame