我认为一个有效的选择是实现TAnimation并覆盖ProcessAnimation.通过TAnimator运行时会自动安排TAnimation.
TGameLoop = class(TAnimation)
protected
procedure ProcessAnimation; override;
end;
[...]
procedure TGameLoop.ProcessAnimation;
begin
//call updates
end;
并像这样开始:
procedure TForm1.FormCreate(Sender: TObject);
begin
FLoop := TGameLoop.Create(Self);
FLoop.Loop := True;
FLoop.Name := 'GameLoop';
FLoop.Parent := Self;
TAnimator.StartAnimation(Self, 'GameLoop');
end;
默认情况下,动画的FPS设置为60.我现在无法弄清楚的一件事是如何通过仅使用TAnimation的属性来计算自上次调用以来的Deltatime.这个对于处理可变帧时间至关重要.但是,你自己使用System.Diagnostics.TStopwatch自己做.在ProcessAnimation开始时停止观察并获得Ticks,在完成ProcessAnimation后开始一个新的.
编辑:
Deltatime的基本示例(自上次呼叫以来的经过时间,以秒为单位).鉴于您在Form1上放置了一个ViewPort3D,添加了名为Cube1的TCube,TGameLoop与Form1(我知道,丑陋但Demopurpose)在同一单元中声明,TGameLoop具有类型为TStopWatch的Field FWatch.
procedure TGameLoop.ProcessAnimation;
var
LDelta: Single;
begin
FWatch.Stop;
LDelta := FWatch.ElapsedTicks / FWatch.Frequency;
Form1.Cube1.RotationAngle.Y := Form1.Cube1.RotationAngle.Y + 50*LDelta;
FWatch := TStopwatch.StartNew();
end;
EDIT2:一个更好的例子,可以在整个游戏生命周期中更好地分配舍入/测量错误.我们从第一帧开始测量,而不是仅在测量之间进行测量. TGameLoop有一个新的Field FLastElapsedTicks(Double)
procedure TGameLoop.FirstFrame;
begin
FWatch := TStopWatch.StartNew();
end;
procedure TGameLoop.ProcessAnimation;
var
LDelta: Single;
LTickDelta, LElapsed: Double;
begin
LElapsed := FWatch.ElapsedTicks;
LTickDelta := LElapsed - FLastElapsedTicks;
FLastElapsedTicks := LElapsed;
LDelta := LTickDelta / FWatch.Frequency;
Form1.Cube1.RotationAngle.Y := Form1.Cube1.RotationAngle.Y + 50*LDelta;
end;