首页 > 解决方案 > 如何使用 IdleHandler 在 Delphi 中设置固定 FPS?

问题描述

我的 Delphi 应用程序中有一个 OpenGL 窗口,我想根据用户的选择使用固定或无上限的 FPS 进行渲染。每渲染一次窗口(例如 30 FPS)似乎可以工作,但不起作用的是计算这些 FPS 并显示它。这很奇怪,因为它适用于未封顶的部分。这是代码,我也用 TStopWatch 尝试过,但我遇到了同样的问题,我在下面解释。

procedure TFoMain.IdleHandler(Sender: TObject; var Done: Boolean);
begin
  if Self.FPS <> 0 then begin
    if (GetTickCount - PrevTime >= (1000 / FPS)) then begin
      StartTime := GetTickCount;
      Render();
      PrevTime := GetTickCount;
      DrawTime := PrevTime - StartTime;
      Inc(TimeCount, DrawTime);
      Inc(FrameCount);
    end;
  end

  else begin
    StartTime := GetTickCount;
    Render();
    PrevTime := GetTickCount;
    DrawTime := PrevTime - StartTime;
    Inc(TimeCount, DrawTime);
    Inc(FrameCount);
  end;

  if (TimeCount >= 1000) then begin
    Frames := FrameCount;
    TimeCount := TimeCount - 1000;
    FrameCount:= 0;
  end;

  Done := false;
end;

至于FPS变量,当设置为 0 时,我将帧定义为无上限。FPS这是我遇到的问题:在无上限 FPS 模式下,一切正常,但一旦我切换到上限 FPS,出于某种原因StartTimePrevTime总是相等的,因此DrawTime变为 0。这导致了这样一个事实,即TimeCount不会增加,我永远不会进入 if 条件,在其中我检查 TimeCount >= 1000 并设置Frames我在窗口中显示的变量。

我很困惑,因为对于无上限和有上限的 FPS 它是相同的确切代码片段,我怎样才能为这些变量获得如此不同的值?我想这可能是一个问题GetTickCount,但事实并非如此,因为我得到了相同的结果TStopWatch

有人可以告诉我我做错了什么或如何正确做吗?

标签: loopsdelphiopenglhandlergettickcount

解决方案


我无法解释为什么当 FPS 设置为零时您会看到不同的操作,但正如您指出 PrevTime 和 StartTime 的结果相同,我会尝试不同的方法:

将 NextTick 和 TimeStart 初始化为 0

procedure TFoMain.IdleHandler(Sender: TObject; var Done: Boolean);
begin
  ThisTick:=GetTickCount();
  if(TimeStart=0) then TimeStart:=ThisTick;

  if ((Self.FPS=0) Or (ThisTick>=NextTick)) then begin
    Render();
    Inc(FrameCount);
    if(FPS<>0) then NextTick:=ThisTick+(1000/FPS);
  end;

  if(GetTickCount()-TimeStart>=1000) then begin
    Frames := FrameCount;
    TimeStart:=TimeStart+1000;
    FrameCount:=0;
  end;

  Done := false;
end;

这会忽略经过的时间,而是使用 GetTickCount 在适当的时间做出响应。正如对您的 OP 的评论中所指出的,这并不能说明 GetTickCount() 的包装!


推荐阅读