【问题标题】:why start a timer in SDL when setting FPS?为什么在设置 FPS 时在 SDL 中启动计时器?
【发布时间】:2010-12-19 18:20:15
【问题描述】:

这是关于lazyfoo 的一组SDL 教程中的this 教程页面。在那里,他首先启动了一个计时器来计算每帧在刷新之前应该保持多长时间。他使用以下方法来做到这一点

if( ( cap == true ) && ( fps.get_ticks() < 1000 / FRAMES_PER_SECOND ) ) { 
 //Sleep the remaining frame time 
 SDL_Delay( ( 1000 / FRAMES_PER_SECOND ) - fps.get_ticks() ); 
} 

虽然我发现 fps.get_ticks() 总是返回 0 (??),所以上面不是不需要 (?),但我们不能完全忽略计时器,只延迟 1000/FPS。

我已经尝试了以下两种方法,并且都给了我同样的东西。我在这里缺少什么,为什么我们需要一个计时器?。

#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include <iostream>
SDL_Surface *background = NULL;
SDL_Surface *screen = NULL;
SDL_Surface *msg = NULL;
const int FPS = 20;

void initialize(void){
    if (SDL_Init(SDL_INIT_EVERYTHING) == -1 ){
        std::cout<<"could not start sdl"<<std::endl;
    }

    screen = SDL_SetVideoMode(640,480,32,SDL_SWSURFACE);
    if (screen == NULL){
        std::cout<<"could not make screen"<<std::endl;
    }

}
void cleanUp(void){
    SDL_Quit();
    SDL_FreeSurface(background);
    SDL_FreeSurface(msg);
}
void loadFiles(void){
    background = IMG_Load("background.bmp");
    msg = IMG_Load("msg.bmp");
    if (background == NULL){
        std::cout<<"could not load background"<<std::endl;
    }
    if (msg == NULL){
        std::cout<<"could not load msg"<<std::endl;
    }
}
void blitSurf(int x,int y,SDL_Surface *source,SDL_Surface *dest){
    SDL_Rect dest_pos;
    dest_pos.x = x;
    dest_pos.y = y;

    if (SDL_BlitSurface(source,NULL,dest,&dest_pos) == -1){
        std::cout<<"could not blit surface"<<std::endl;
    }
}
void update(void){
    if (SDL_Flip(screen) == -1 ){
        std::cout<<"could not update screen"<<std::endl;
    }
}

int main(int argc,char *argv[]){
    initialize();
    loadFiles();

    bool running = true;
    bool cap = false;
    int msg_pos_y = 0;
    int start = 0;
    int temp = 0;
    SDL_Event event;
    while (running == true){
        start = SDL_GetTicks();

        while (SDL_PollEvent(&event)){
            if (event.type == SDL_KEYDOWN){
                if (event.key.keysym.sym == SDLK_c){
                    if(cap == false){
                        cap = true;
                        std::cout<<"cap set to, true"<<std::endl;
                    }else{
                        cap = false;
                        std::cout<<"cap set to, false"<<std::endl;
                    }
                }
            }   
            if (event.type == SDL_QUIT){
                    running = false;
                    std::cout<<"Quit was pressed"<<std::endl;
            }
        }

        blitSurf(0,0,background,screen);
        if (msg_pos_y < 640){
            blitSurf(200,msg_pos_y,msg,screen);
            msg_pos_y++;
        }else{
            msg_pos_y = 0;
            blitSurf(200,msg_pos_y,msg,screen);
        }
        update();


        if ( (cap == true) && ( (SDL_GetTicks()-start) < (1000/FPS) ) ){
            SDL_Delay( (1000/FPS) - (SDL_GetTicks()-start) );
        }

        /* this works as well ??
        if ( cap == true ){
            SDL_Delay(1000/FPS);
        }
        */
    }

    cleanUp();
    return 0;
}

【问题讨论】:

    标签: c++ c sdl frame-rate


    【解决方案1】:

    假设你想要 50 fps。

    1000 毫秒 / 50 = 20 毫秒延迟。

    但是无论你在做什么,渲染、计算物理、人工智能都需要时间。假设我写的所有这些东西都需要 10 毫秒。您有 1000 毫秒/(20 毫秒延迟 + 10 毫秒其他所有时间)= 33.3 帧/秒。您需要从延迟中减去这 10 毫秒。

    【讨论】:

    • 干杯,但是我编写了一个测试程序,它在一次 while 循环迭代中调用 SDL_GetTicks() 两次,第一次在最顶部,第二次在底部。它们都产生相同的结果,并且时间没有不同。如果循环更复杂并且有人工智能和物理等等,时间会不会有所不同?。
    • 是的,如果您在它们之间做一些耗时的事情,它们会有所不同。
    【解决方案2】:

    我不是专家,但他所做的是:一旦完成运行 sdl 应用程序的主循环(绘制 blitting 和所有这些东西),当你做你的事情时,时间可能已经过去了一点,例如,如果绘制帧需要 10 毫秒,您必须等待 (1000/FPS) - 10 毫秒直到下一帧,否则您的帧将持续太长时间。

    【讨论】:

    • 是的,我就是这么想的,但是在一次循环迭代中两次调用 SDL_GetTicks() 函数会得到相同的结果(?)。所以在 if 语句中,fps.get_ticks() 实际上只返回 0(来自 get_ticks 函数内部的SDL_GetTicks() - startTicks;)。这就是我感到困惑的原因。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多