תנועה חלקה בכל קצב פריימים
חלק מהיחידה צליל ותחושת משחק במסלול ה-Pygame של Coddy. שיעור 19 מתוך 23.
x += (target_x - x) * 0.1 מתקדם עשירית מהדרך בכל פריים. בקצב של 60 פריימים בשנייה, מדובר ב-60 צעדים בשנייה; במחשב איטי שמצליח להציג רק 30, מדובר ב-30 צעדים, ולמעגל לוקח פי שניים זמן להגיע. לחצו על F כדי לראות: המשחק פועל בקצב של 30, והכול נע באיטיות רבה יותר.
הפתרון הוא למדוד זמן. clock.tick() מחזירה את מספר אלפיות השנייה מאז הפריים האחרון. כשמחלקים ב-1000 מקבלים את dt, משך הפריים בשניות: בערך 0.017 בקצב של 60 פריימים בשנייה, ו-0.033 בקצב של 30.
dt = 1 / 60 # לפני הלולאה
...
step = min(1, 6 * dt)
x += (target_x - x) * step
...
dt = clock.tick(fps) / 1000בפריים ארוך יותר הצעד גדול יותר, ולכן המעגל עובר את אותו המרחק באותו זמן בכל קצב פריימים. המספר 6 קובע את המהירות: בקצב של 60 פריימים בשנייה, 6 * dt הוא בערך 0.1, אותה עשירית כמו קודם. min(1, ...) מונעת מפריים ארוך מאוד להתקדם מעבר ליעד.
אותו עיקרון חל גם על תנועה רגילה: player_x += 240 * dt הוא 240 פיקסלים בשנייה, בלי קשר לקצב הפריימים. רוב המשחקים הקטנים מקבעים את הקצב באמצעות tick(60) ולא צריכים זאת אף פעם; השתמשו ב-dt כשהקצב עשוי להשתנות.
אתגר
בינוניF מעביר את המשחק בין 60 ל־30 פריימים בשנייה. דאג שהתנועה המדורגת תימשך אותו זמן בשני המצבים:
- הגדר
dt = 1 / 60לפני הלולאה. - בסוף הלולאה, הגדר
dt = clock.tick(fps) / 1000. - הזז באמצעות
step = min(1, 6 * dt)במקום 0.1:x += (target_x - x) * step, ובאותו אופן גם עבורy.
נסו בעצמכם
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()
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה צליל ותחושת משחק
תרגלו בעצמכם: Pygame אונליין