Jump to content
Sign in to follow this  
DavidRM

Node.JS Game Loop

Recommended Posts

Here is my Smart Mobile Studio adaptation of the Node.JS "node-gameloop" module.

My primary modification was some code to make the *next* interval line up with the desired number of ms per tick. I also tightened the window for choosing SetTimeout vs SetImmediate.

I needed this to provide the beating heart of Paintball Net's simulation engine. Which, sure, only beats 10 times per second, but I wanted it to be as accurate as possible. 🙂

-David

unit UPBNGameGameLoop;

interface

uses 
  System.Types,
  System.Types.Convert,
  System.Time,
  System.Streams,
  System.Reader,
  System.Writer,
  System.Device.Storage,
  SmartNJ.System,
  SmartNJ.Streams,
  SmartNJ.Device.Storage,
  SmartNJ.Application,
  NodeJS.Core;

var
  GameLoopActive: boolean;

type
  TGameLoopCallback = procedure(delta: float);

procedure StartGameLoop(update: TGameLoopCallback; msInterval: integer);
procedure StopGameLoop;

implementation

procedure SetImmediate(const Entrypoint: TProcedureRef); external 'setImmediate';

const
  Seconds2Nano = 1e9;
  Nano2Seconds = 1 / Seconds2Nano;
  MS2Nano = 1e6;
  Nano2MS = 1 / MS2Nano;

var
  _loopProc: TGameLoopCallback;
  _loopLengthHR: float;
  _loopPrevHR, _loopTargetHR: float;

function GetHRTime: float;
var
  hrTime: Variant;
begin
// I need a more up-to-date node to use the bigint() function.
//  asm
//    @Result = process.hrtime.bigint();
//  end;
  asm
    @hrTime = process.hrtime();
  end;
  Result := (hrTime[0] * Seconds2Nano) + hrtime[1];
end;

procedure DoGameLoop;
var
  now, delta: float;
  remaining: integer;
begin
  if GameLoopActive then
  begin
    now := GetHRTime;
    if now >= _loopTargetHR then
    begin
      delta := now - _loopPrevHR;
      _loopPrevHR := now;
      _loopTargetHR := now + _loopLengthHR;
      if delta > _loopLengthHR then
      begin
        _loopTargetHR -= (delta - _loopLengthHR);
      end;
      _loopProc(delta * Nano2Seconds);
    end;
    if GameLoopActive then
    begin
      remaining := Trunc((_loopTargetHR - GetHRTime) * Nano2MS);
      if remaining >= 4 {16} then
        SetTimeout(DoGameLoop, remaining)
      else
        SetImmediate(DoGameLoop);
    end;
  end;
end;

procedure StartGameLoop(update: TGameLoopCallback; msInterval: integer);
begin
  if not GameLoopActive then
  begin
    GameLoopActive := True;
    _loopLengthHR := msInterval * MS2Nano;
    _loopProc := update;
    _loopPrevHR := GetHRTime;
    _loopTargetHR := _loopPrevHR;
    SetImmediate(DoGameLoop);
  end;
end;

procedure StopGameLoop;
begin
  GameLoopActive := False;
  _loopProc := nil;
end;

end.

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...