Lesson 01 — Game Loop & Timestep
Ba mô phỏng chạy thật bằng requestAnimationFrame: thấy tận mắt vì sao phải nhân Δt,
fixed vs variable timestep với accumulator, và đồng hồ FPS / frame-budget thực.
1. Frame-rate độc lập — Δt vs cộng hằng số
Hai viên bi cùng đặt mục tiêu 100 px/giây. Bi hồng cập nhật x += v·Δt (đúng);
bi xám cộng hằng số x += k mỗi frame (sai). Kéo slider giả lập FPS:
bi hồng luôn về đích cùng lúc ở mọi FPS; bi xám nhanh dần khi FPS cao.
x += 100·Δt (đúng)
hằng số: x += 1.67/frame (sai)
▏ vạch đích = 100 px/giây × số giây
2. Fixed vs Variable timestep — accumulator
FPS thật dao động (mô phỏng lag ngẫu nhiên). Mỗi frame dồn Δt thật vào
accumulator, rồi tiêu thành các bước cố định FIXED = 1/60 s.
Số ô hồng = số bước vật lý chạy trong frame đó: lag → chạy nhiều bước đuổi kịp; frame ngắn → 0 bước.
Bi hồng dùng fixed timestep (nội suy theo accumulator → mượt & tất định). Tổng số bước luôn bám sát tổng thời gian thật ÷ FIXED — vật lý không phụ thuộc nhịp render thất thường.
3. FPS & Frame budget meter
Đồng hồ FPS thật của trình duyệt bạn (đo từ Δt thật của requestAnimationFrame).
Bấm "Tải nặng giả lập" để cố tình đốt thời gian mỗi frame → xem frame budget bị ăn mòn và FPS tụt.
4. Bảng so sánh nhanh
| Variable timestep | Fixed timestep | |
|---|---|---|
| Δt mỗi update | thay đổi (Δt thật) | cố định FIXED |
| Code | đơn giản | cần accumulator |
| Tất định? | không | có |
| Ổn định vật lý cứng? | kém (dễ nổ với Δt to) | tốt |
| Rủi ro | xuyên tường khi Δt vọt | spiral of death (nếu không kẹp) |
| Hợp cho | prototype, chuyển động đơn giản | vật lý, netcode, replay |
Chi tiết spiral of death và cách kẹp Δt: xem README §4.3 (nút 📖 ở góc).