Time-based movement thay vì sleep trong game loop

Khi một entity cần chuyển động chậm hơn frame rate của game (ví dụ snake step mỗi 120ms trong khi loop chạy 60fps), có hai cách viết — và sự khác biệt giữa chúng là một trong những bài học bản lề khi học game programming.

Hai cách viết, một câu hỏi đảo ngược

Cách blocking — sleep trong update của entity:

void Snake::Update() {
    SDL_Delay(60);   // block cả thread 60ms
    move();
}

Cách time-based — entity giữ timestamp riêng và poll:

void Snake::update() {
    if (SDL_GetTicks() - this->last_update > SPEED) {
        move();
        this->last_update = SDL_GetTicks();
    }
}

Khác biệt cốt lõi là câu hỏi: cách đầu hỏi “đã sleep đủ chưa?” (block tới khi đủ), cách sau hỏi “đã đủ thời gian từ lần trước chưa?” (return ngay nếu chưa, không làm gì). Một là blocking, một là polling. Cùng giải quyết “snake step mỗi 60ms” nhưng hệ quả khác nhau hoàn toàn.

Vì sao sleep trong update phá game loop

Trong 60ms SDL_Delay đó, toàn bộ game loop bị block:

Sleep trong update vi phạm hợp đồng ngầm của game loop: update phải hoàn thành trong một burst ngắn để loop có cơ hội quay tiếp. Đây là cùng nguyên lý cooperative scheduling đã thấy ở Điều khiển thread bằng cooperative event.

Per-entity clock và pattern decoupling

Cách time-based mở ra ba khả năng:

Liên hệ ngoài game programming

Cùng tư duy “không block, schedule công việc” xuất hiện ở nhiều nơi:

Sleep trong vòng lặp chính là anti-pattern xuyên ngành. Khi gặp tình huống “tôi muốn chậm lại”, câu hỏi đúng là “ai có quyền chậm lại — tôi hay loop?” — câu trả lời gần như luôn là loop.

Trải nghiệm cá nhân

Phát hiện này đến từ bug FPS drop khi viết snake/Snake.cpp:25 (sleep trong update) thời 2016–2017. Phiên bản sau (doge_snake/main.cpp:58) đã chuyển sang time-based và tổng quát hoá thành per-entity rate trong doge_space/doge.cpp. Cá nhân không nhớ tư duy lúc sửa, nhưng đối chiếu hai phiên bản code cho thấy đã đi qua ba bước chuyển: đảo câu hỏi (blocking → polling), per-object clock, tổng quát thành per-entity rate. Chi tiết trong transcript phỏng vấn.

Cập nhật: 2026-05-29