PDA

View Full Version : Game loop without using DXTImer.



wodzu
07-01-2006, 01:17 PM
I am thinking about doing time-base independant project.
Any ideas where I could put my main loop? Do I have to process system messages? As far as I know/see DXTImer.OnTImer do its for me.

Regards,

Wodzu

AthenaOfDelphi
07-01-2006, 02:15 PM
Hi wodzu,

You have a couple of options. The first, and perhaps easiest is to use a timer that fires once, then within the event handler, you create a repeat until loop that will terminate when you set a boolean variable. As part of this loop, you must call application.processMessages or your app will appear to hang.

Quick example:-



....

procedure TForm1.formShow(sender:TObject);
begin
tmrMainLoop.enabled:=true;
end;

procedure TForm1.tmrMainLoopTimer(sender:TObject);
begin
tmrMainLoop.enabled:=false;
fTerminate:=false;
repeat
// Do your processing here

application.processMessages;
until (fTerminate);

application.terminate;
end;

....



The other option is to create a seperate thread that does the work. This has the advantage that you won't have to call application.processMessages since once you create the thread and its running, the VCL thread that normally handles messages will be idle and will as a consequence process the messages itself. Now that multicore/multiprocessor machines are becoming more common, this may be the better approach since the OS should split the load across cores/processors.

For example...



type
TMyThread = class(TThread)
public
procedure execute; override;
end;

....

procedure TForm1.formShow(sender:TObject);
begin
fMyThread:=TMyThread.create(true);

// Pass any objects the thread needs access to here using properties
// Link up the threads onTerminate handler if you want to it up yourself
// or set the freeOnTerminate property to true and it will clean itself up
// when it terminates

fMyThread.resume;

// From this point, your thread is running and the VCL thread will become
// idle.
end;

procedure TForm1.quitButtonClick(sender:TObject);
begin
fMyThread.terminate;
end;

procedure TMyThread.execute;
begin
// Initialise

repeat
// Do your processing here
until (self.terminated);

// Clean up
end;



Although this is the easiest way to implement a threaded version, its not great since your main app doesn't get feedback that the thread is terminated. Depending on what the thread does, this may not be needed, but just in case, heres a more complex example, that passes certain objects via the constructor and also provides the main app with feedback that the thread has terminated.


type
TMyThread = class(TThread)
private
fDXD : TDXDraw;
fINI : TIniFile;
public
constructor create(dxd:TDXDraw;ini:TIniFile;terminateHandler:T NotifyEVent); override;
procedure execute; override;
end;

....

procedure TForm1.formShow(sender:TObject);
begin
fMyThread:=TMyThread.create(self.dxdraw,self.theCo nfigIni,self.threadTerminated);
end;

procedure TForm1.quitButtonClick(sender:TObject);
begin
fMyThread.terminate;
end;

procedure TForm1.threadTerminated(sender:TObject);
begin
fMyThread.free;
application.terminate;
end;

constructor TMyThread.create(dxd:TDXDraw;ini:TIniFile;terminat eHandler:TNotifyEVent);
begin
inherited create(true);

self.freeOnTerminate:=false;

fDXD:=dxd;
fIni:=ini;

self.onTerminate:=terminateHandler;

self.resume;
end;

procedure TMyThread.execute;
begin
// Initialisation

repeat

// Processing here

until (self.terminated);

// Clean up
end;



I can't comment on whether either of these approaches will work as described with Free Pascal.

The only real problems with the threaded approach are that you must become mindful of shared resources and that some components may not be thread friendly.

Hope this helps. It may be that the more experienced game developers know better ways of achieving the same thing, but if I was going to do what you've described, these two are the ways I'd consider.

wodzu
07-01-2006, 03:03 PM
Thank You for Your suggestions.
I definitely consider using thread in my application.


The only real problems with the threaded approach are that you must become mindful of shared resources and that some components may not be thread friendly.
I think that this problem can be resolved via Synchronize metod which is described in Delphi help.

Regards.

JSoftware
07-01-2006, 06:02 PM
i usually hook the onidle message for a window i create myself. i think that's the fastest and most failsafe approach i know of. either that or just put a main loop that fetches messages in the end and processes them. IF you're doing the vcl way or delphi form way then i would either go with a endless loop throwing a application.processmessages in the end or the threaded approach athena showed

LP
07-01-2006, 08:28 PM
I would go against thread approach. It's a lot of overhead for the application *and* the CPU (you will have to synchronize a lot, especially when rendering) and because of it, you will lose smooth animation, get a lot of bugs (which will be hard to find) and your code will become very complex quickly.

I say this a lot, but the simplest solution is usually the best one. There are many articles about organizing game's main loop, just Google for it. Here's a link of interest: Game Programming Genesis, Part I : Beginning Windows Programming (http://www.gamedev.net/reference/articles/article1229.asp) (it's not in Pascal, but you can get the idea).