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.

Δt: x += 100·Δt (đúng) hằng số: x += 1.67/frame (sai) ▏ vạch đích = 100 px/giây × số giây
Δt mô phỏng
0.0167
giây/frame
Bi Δt (hồng)
0
px · ≈ 100·t
Bi hằng số (xám)
0
px
Thời gian mô phỏng
0.0
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.

Accumulator (0 → FIXED, vạch đen = ngưỡng FIXED)
Δt thật frame
0.000
giây
Bước/frame
0
lần update(FIXED)
Tổng bước
0
× FIXED
Accumulator dư
0.000
giây < FIXED

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.

0 ms
FPS thật
1 / Δt
Δt thật
ms/frame
Frame budget
16.67
ms (mục tiêu)
Còn dư / vượt
ms

4. Bảng so sánh nhanh

Variable timestepFixed timestep
Δt mỗi updatethay đổi (Δt thật)cố định FIXED
Codeđơn giảncần accumulator
Tất định?không
Ổn định vật lý cứng?kém (dễ nổ với Δt to)tốt
Rủi roxuyên tường khi Δt vọtspiral of death (nếu không kẹp)
Hợp choprototype, chuyển động đơn giảnvật lý, netcode, replay

Chi tiết spiral of death và cách kẹp Δt: xem README §4.3 (nút 📖 ở góc).