SDL_Delay() ở MacOS

Sau 1 hồi tìm kiếm trên Google thì dường như hàm bị lỗi ở MacOS ạ.
Thay vào đó, mình có thể dùng:

for(int i = 0; i < time_to_pause; i++){
	SDL_PumpEvents();
	SDL_Delay(1);
}

Nhưng mà cách này làm cho nó bị dừng lâu hơn mong đợi, vì vậy có cách nào hay hơn không ạ
Em cảm ơn !

SDL_Delay(time_to_pause);

:V :V

sao lại gọi SDL_PumpEvents() làm gì??

3 Likes

Như em nói thì SDL_Delay() ở MacOS nó bị lỗi anh ạ, nó ko cho cái cửa sổ hiện lên luôn á anh.

Update: Sau khi đọc link bài viết trên thì em nhận ra thêm là sẽ ko bị lỗi nếu trước SDL_Delay() đã có vòng lặp sự kiện bất kì @@

để a viết cho e cái vòng lặp main loop của SDL :V :V

cấu trúc của vòng lặp chính của SDL2 là

// main loop
for (bool quit = false; !quit;) {
    // handle events
    // process game logic
    // draw & display
}

có 3 phần chính:

    1. Xử lý events như gõ phím, bấm chuột, resize màn hình v.v…
    1. Xử lý logic của game như là update physics
    1. Vẽ và hiển thị ra màn hình

3 phần này để thứ tự thế nào cũng được :V vì khi vòng for lặp liên tục kia nó sẽ chạy theo thứ tự 123123123123 thì khi nhìn vào có thể thấy nó lặp là 123.123 hay 231.231 hay 312.312 gì cũng được :V

nếu 3 phần này xử lý nhanh quá, ví dụ mỗi phần 0.1ms thì 3 phần chỉ có 0.3ms, trong 1 giây chạy 3333 lần tổng cộng thì display 3333 lần/giây, tương đương với 3333fps :V Ngoài ra CPU xử lý events/logic liên tục thì nó chạy cpu lên tối đa 100% cpu, trong khi màn hình máy tính chỉ refresh 60/120/144Hz(fps) là hết :V vì vậy nên cần delay để giảm fps xuống.

gọi phần delay này là phần 4. Phần 4 này có thể thực hiện theo nhiều cách:

  • Cách đơn giản là code 1 dòng :V gọi SDL_Delay(1000 / MAX_FPS); với MAX_FPS = 60 hay gì đó :V nhưng ko bảo đảm fps chạy đều đều 60 mà chậm hơn và rất bất định, có thể nhảy 30-60fps tùy thích :V tùy vào 3 phần đầu xử lý nhanh chậm thế nào, ví dụ 3 phần đầu xử lý nhanh 1ms thì 1 frame lúc này là 17ms ~ 60fps, 3 phần đầu xử lý chậm 10ms thì 1 frame lúc này là 26ms ~ 40fps
  • Để giảm bớt vấn đề frame time ko cố định này thì có thể đo thời gian chạy 3 phần đầu chạy như thế nào, ví dụ là process_time, rồi so sánh với FRAME_TIME(= 1000 / MAX_FPS), nếu process_time bé hơn FRAME_TIME thì gọi SDL_Delay(FRAME_TIME - process_time), còn ko thì khỏi delay :V Cách này thì tuy ko tránh khỏi những frame có thời gian xử lý lâu hơn FRAME_TIME ví dụ = 16ms, nhưng với các frame khác có thời gian xử lý lẹ thì luôn cố định frame time là 16ms.
  • Cách 3 là ko cần gọi SDL_Delay luôn :V bằng cách kêu thằng SDL nó sync frame time với screen refresh rate. Khi tạo SDL_Renderer thì pass thêm flag SDL_RENDERER_PRESENTVSYNC vào là xong, khi renderer nó display nó sẽ sync với screen cho mình luôn. Ví dụ tạo renderer:
    renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    
    hoặc nếu xài OpenGL để render thì toggle vsync của OpenGL :V

code cho vòng lặp main loop của SDL, nếu có xài vsync vài xài SDL_Renderer:

SDL_Renderer* renderer = SDL_CreateRenderer(window, -1,
    SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

// main loop
for (bool quit = false; !quit;) {
    // handle events
    for (SDL_Event evt; SDL_PollEvent(&evt);) {
        if (evt.type == SDL_QUIT) {
            quit = true;
            break;
        }
    }

    // process game logic
    // (nothing to process)

    // draw & display
    SDL_RenderClear(renderer); // clear screen
    // draw... (nothing to draw)
    SDL_RenderPresent(renderer); // display
}

nếu ko xài vsync thì

const int kMaxFps = 60;
const int kMaxFrameTime = 1000 / kMaxFps;

SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

// main loop
for (bool quit = false; !quit;) {
    const auto startFrameTime = SDL_GetTicks64();

    // handle events
    for (SDL_Event evt; SDL_PollEvent(&evt);) {
        if (evt.type == SDL_QUIT) {
            quit = true;
            break;
        }
    }

    // process game logic
    // (nothing to process)

    // draw & display
    SDL_RenderClear(renderer);
    // draw... (nothing to draw)
    SDL_RenderPresent(renderer);

    // delay
    const auto processTime = SDL_GetTicks64() - startFrameTime;
    if (processTime < kMaxFrameTime)
        SDL_Delay(kMaxFrameTime - processTime);
}
5 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?