Archived

This topic is now archived and is closed to further replies.

Do's And Don'ts ?

This topic is 6335 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a simple questions: How do you gain speed when programming a game using Delphi / DelphiX ? I''ve read somewhere that you shouldn''t use double data types. But as I don''t know how to test this or or maybe haven''t written a big enough program / game to be able to really test it - is there someone of you who whould know what to do? Basically, what''s the do''s and don''ts when doing a game. thanks guys.

Share this post


Link to post
Share on other sites
Hi Olona,

Here''s a couple of do''s and don''ts,

- Don''t use round(); use trunc(); instead.

- When creating an imagelib, set all your images to use video memory, don''t set them to use system memory.
When creating a game in 16 bit video mode or higher, use
a program like photoshop or paintshop pro( or equiv) to reduce the amount of colors of your images to 256.
Your images will still look great but at 1/3 of the size of a full 16 bit image. no need to worry about palettes either, you''re in 16 bit mode, every image has it''s own palette( sortof).

Another big no no i''ve seen around is this:

enemyship : array[0..100] of tEnemySpriteship; // from class TimageSprite

Procedure tEnemySpriteship.domove(movecount:integer);
Var
i:integer;
begin
for i:=0 to 99 do
begin
enemyship.x:=somethingelse;
end;
end;

The above is a cpu killer, prolly one of the biggest no no out there

it''s like doing this:
for m:=0 to 99 do
begin
for i:=0 to 99 do
begin
enemyship[i].x:=somethingelse;
end;
end;

Since domove is called for everysprite automatically, there''s no need to call em one by one in a loop.

you just need to call it like so:
Procedure tEnemySpriteship.domove(movecount:integer);
begin
x:=somethingelse;
end;


Well, that''s it for now.
There''s tons more i could write about but this is what comes to mind right now.

Hope it helped a bit.
Gook luck.

Gunner
Sysimage inc.

Share this post


Link to post
Share on other sites
This topic could get quite long, but here are some things I use to speed up DelphiX...

1. Avoid using DxDraw.Canvas at all costs. Use turboPixels, PixelCore, etc. to draw lines and put text on the screen.

2. Avoid DrawAlpha and DrawADD for bigger areas. And if you use it in small areas remember to set your transparent color.

3. Do your own cropping and use BltFast when you can.

4. Keep your DXGs out of your EXE for larger projects.

5. Make check boxes for DoFlip and WaitVBlank -- some newer vid cards and monitors don''t need these options.

6. Don''t use DxImageList.Find(''item'') in your final build. Use DxImageList[item] where item is a CONST.

7. Don''t use DxDraw.Width or DxDraw.Height in your game loop -- these are slower than assigning them to globals.

8. Use 512x384x16 for scrolling/action games/demo code if you can. Its 25% faster then 640x480x16

9. Use 8-bit color if possible (i.e. Diablo, Starcraft, AoE) you can do some neat tricks and it''s very fast.

10. Put a FPS counter on screen and experiment with different ordering and loops.



[ turbo | turbo.gamedev.net ]

Share this post


Link to post
Share on other sites
quote:
Original post by turbo

3. Do your own cropping and use BltFast when you can.


When using DelphiX''s Draw method, it performs BltFast itself then if it doesn''t work, tries Blt. BTW, the BltFast error code seems to be inconsistent with the DirectX documentation. I would recommend to modify the error checking line in DirectDrawSurface.Draw and replacing it with "if DXResult<>DD_OK" instead of "DXResult=WhateverErrorCodeItUses". That''s what I''m doing for my project.

quote:
5. Make check boxes for DoFlip and WaitVBlank -- some newer vid cards and monitors don''t need these options.


DoFlip is only used in fullscreen mode. If disabled, DelphiX will Blt the back surface to the front surface automatically. If enabled, it will flip the back surface with the front surface. It would be wise to leave it when using FS mode, IMHO.


--
Kyodai Mahjongg
kyodai.com

Share this post


Link to post
Share on other sites
Guest Anonymous Poster

>When using DelphiX''s Draw method, it performs
>BltFast itself then if it doesn''t work, tries
>Blt. BTW, the BltFast error code seems to be
>inconsistent with the DirectX documentation. I
>would recommend to modify the error checking
>line in DirectDrawSurface.Draw and replacing
>it with "if DXResult<>DD_OK" instead >of "DXResult=WhateverErrorCodeItUses". That''s
>what I''m doing for my project.

I find that BLTFASTing a "cropped" surface, like a scrolling bitmap (i.e. Miniverse) gain about 20% on newish video cards over Hori''s DRAW. This is simply "thinking around" why the BLTFAST would fail in the first place.

Share this post


Link to post
Share on other sites
quote:
Original post by Anonymous Poster
I find that BLTFASTing a "cropped" surface, like a scrolling bitmap (i.e. Miniverse) gain about 20% on newish video cards over Hori''s DRAW. This is simply "thinking around" why the BLTFAST would fail in the first place.



According to the DX SDK help files, BLTFAST is *as fast* as BLT when you use hardware acceleration. If you don''t use it, BLTFAST is faster. But BLTFAST will only work on video to video transfer, etc.
I think that Hori''s DRAW system (Crop first, then try to BltFast, if it doesn''t work then Blt) is the safest of all...


--
Kyodai Mahjongg
kyodai.com

Share this post


Link to post
Share on other sites
One big mistak of delphiX coders is to use the main game loop in a timer. Simple set the timer of any package (Native, DelphiX, RXLib) to 0 is not enough for the speed that a game needs. Moreover, you share precious time of graphics render with the fight of Windows messages vs Delphi''s VCL...
The way is to slice the main game turn in two parts and put each one in a clean thread. Part 1: The read of player inputs and other moves calculations. Part 2: Graphic renders.
Ok, all of us have fear of threads, but they are more easy that we think:

// Variables for the thread control
var StopRender, RenderStopped: Boolean;
HRenderThread: DWORD;

procedure Render;
begin
Repeat
// ...
// Do the render stuff here
// ..
until StopRender;
Sleep(X) // Make some calculations if needed to control the velocity
RenderStopped := True;
end;

When the game are ready to begin the main loop, start the thread with:

HRenderThread := CreateThread(nil,0,@Render,nil,0,AnyVarIntegerHere);

This function "CreateThread" is an import of the Kernel32.dll and is declared on windows.pas.

To stop the thread do:

StopRender := True;
Repeat until RenderStopped;
CloseHandle(HRenderThread);

Easy hu? But take care when working with threads... All is happening at the same time, so, do not change or destroy anything that the thread is using!

The reward is the smoothest scrool and draw that you ever seen on a DelphiX game.
Try!

Till the next!

Share this post


Link to post
Share on other sites
quote:

One big mistak of delphiX coders is to use the main game loop in a timer. Simple set the timer of any package (Native, DelphiX, RXLib) to 0 is not enough for the speed that a game needs. Moreover, you share precious time of graphics render with the fight of Windows messages vs Delphi''s VCL...
The way is to slice the main game turn in two parts and put each one in a clean thread. Part 1: The read of player inputs and other moves calculations. Part 2: Graphic renders.
Ok, all of us have fear of threads, but they are more easy that we think:



I''ve always used Carlos''s threaded timer or the Application.OnIdle event to squeeze that extra speed out. How about whipping up a sample app to show us how it''s done for real?



[ turbo | turbo.gamedev.net ]

Share this post


Link to post
Share on other sites
quote:
Original post by turbo

[quote]
I''ve always used Carlos''s threaded timer or the Application.OnIdle event to squeeze that extra speed out. How about whipping up a sample app to show us how it''s done for real?



The simple fact of use a procedure (event, in this case) of a timer call, or the cited Application.OnIdle as loop implies on the game patiently waiting for the Delphi while it is pushing and poping registers of control of execution flow. A basic rule of optimized code on Delphi or any knowed language, since 16 bits apps, mainly now on 32 bits apps is: Less functions and procedures calls on loops, less time wasted with pushs and pops, faster code. So, if we need a loop, better do it on a real loop, on a single place, with a repeat until, or a while do end, without functions, procedure or events calls. But we can''t make this loop on the main thread, so, this is the why of use an independet thread.
About the sample app, well, it is the code above and is sufficiently clearly to anyone use and see the results.

Till the next

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I don''t think that two seperated Threads are a good idea.
I use the old simply way.
For me, I use a repeat until loop as "mainloop". It''s started after everything is set up and initialized, runs until certain conditions make it stop (an error, user input etc.) and after that everything is cleared, shutdown etc.
In this loop you first check for User input, react on it then draw everything and finally flip.
Easy huh ? AND fast.
This of course won''t work with DelpiX.

[ Ampaze | www.crazyentertainment.net ]

Share this post


Link to post
Share on other sites
Opposition to L-Tryosine:

Making two different threads as you explained is VERY BAD and IMPOSSIBLE idea. I agree that making unit movement in separate thread would work (although problematic - see below), but if you put renders in seperate thread - you'll completely or partially block the main thread. Why?! Because as Delphi Help says most of the VCL routines are executed in main thread so u need to sync with them. If you do renders in separate thread - you'll call main thread very often and the main thread will be almost blocked. As a result, you won't be able to react on key presses and other events. Note that TIMING routines from MMSystem which are commonly used are also executed in main thread. Even if you don't draw and don't process anything - you may execute these routines to calculate the FPS you're getting and in 200 FPS you'll block your main thread again, only using one timing routine. ...and if you don't render and process anything yet - your code will execute at 1000-2000 FPS...

Keep in mind that WinNT has less precise timers (although you can adjust the precision - it's not recommended to change the precision for the whole time your game executes). The only way to "move your units" at the same speed in thread would be using timers, which, as I said, will block your thread.

Still, using Sleep method isn't good idea because it's not too precise and your units will jerk as well as your renderings.

Oh, almost forgot: by "blocking main thread" I mean that you will call functions from main thread so quickly that it won't be able to respond to events (by that I mean ALL EVENTS), etc.

My another point is - why will someone need to "ignore" main thread events to gain more speed?! Why would you continue to move units, etc if the player has clicked with the mouse?! You'd better stop unit movement and make necessary modifications to variables, etc and then resume the thread execution.

And my last point - having two or three threads in one program - you'll get very slow perfomance because the threads will interfere with each other, synchronizing and doing shit like this. Besides WinNT gives fixed amount of CPU to every thread so you won't be able to get 100% of CPU on some specific thread.

As you see, my position here is - THREADS ARE NOT USED USUALLY IN GAME DEVELOPMENT (I mean that they're not common).

Before I used two threads like L-Tryosine said, and was saying it was good way. After I installed WinNT5 and got my main thread blocked - I studied my method and found its incompetence. Currently I'm using OnIdle event where I calculate FPS rate, do renderings and movement, which is done accourding the FPS. in the loop I use two FPS rates - one which is updated every frame and unit movement depends on this one. Since this timer is updated every frame, the program is very responsive to speed changes (so if your rendering are slowed down - unit movement is changed accourding to it). The second timer is used only as information of how fast the game is running, it's updated every 30th frame.


Hope that's enough
Lifepower

Edited by - Lifepower on July 27, 2000 10:53:17 AM

Edited by - Lifepower on July 27, 2000 11:05:24 AM

Edited by - Lifepower on July 27, 2000 11:09:55 AM

Edited by - Lifepower on July 27, 2000 11:18:38 AM

Share this post


Link to post
Share on other sites
Don''t use TTimer or *whatever*timer that gives you events.
Don''t use threads unless you really need to.

Do use the high precision counters as your time reference.
Do use time-based progression, like in

MainLoop
deltaTime = CurrentTime - lastTime
lastTime = CurrentTime
Get UserInput and manage your stuff, proportionnaly to deltaTime
Render a new frame
Loop Forever (almost)

f.i. if my bullet move at 10 meters per second, I will only move it by 10*deltaTime meters (deltaTime expressed in seconds) at each step.
Similarly, if pushing the joystick forward accelerates your vehicle, it''s action will be expressed as an acceleration, like ''5 meters per second per second'', and it will be used in
''new speed = old speed + acceleration * deltaTime'', etc.

The additionnal multiplications have a negligible impact in terms of game speed and allow clean movement, whatever the time it takes for a frame.

Additionnaly, you may not Render a frame each time, if DirectX/OpenGL is still busy rendering the last one, just ignore the rendering phase and move on. This avoids stalling the renderer and greatly helps a network code among other things (better ping), especially when a 3D hardware is present.


Eric Grange
http://glscene.org

Share this post


Link to post
Share on other sites
I think it is possible to make the game loop on the main thread. Using application.processmessages-procedure in every time when running the loop you will be able to force your program to handle all the messages. This way you can react to key presses and other events. It''s also faster because you don''t have to wait any timer events. I tried it and it worked perfectly!

Share this post


Link to post
Share on other sites
quote:
Original post by Some1

I think it is possible to make the game loop on the main thread. Using application.processmessages-procedure in every time when running the loop you will be able to force your program to handle all the messages. This way you can react to key presses and other events. It''s also faster because you don''t have to wait any timer events. I tried it and it worked perfectly!


Also from personal experience, I wouldn''t recommand Application.ProcessMessages for all cases though...

(That was a useless message, wasn''t it ? )


--
Kyodai Mahjongg
kyodai.com

Share this post


Link to post
Share on other sites
Here we go again:

Lifepower, simply I did not understand the first paragraph.
What you want to say with "stop main thread"??? We are creating another one exactly to avoid interference with the main thread...
The main thread definitively it is not blocked, delayed or something like this, what eliminates most of the disadvantages cited for you. A basic prove of this, is that while I am building the game, I close with a click in the DXDraw, whose the event is in the main thread. And... Man, some of techinical data that you cited simply are not correct! Let''s get, for example, what you said about "threads slowing down the CPU". I could get the basic example of thread that comes with Delphi, but we are not on an amateur site. Open the winsight and take a ride on the amount of threads running. About your question in "need to ignore the messages": Working by my way, we just let Delphi care about the messages, without stopping our game. Is much interence, ask you. YES, anwser you, after opened the source of TForm, TComponent, etc.

Sorry about your bad experience with threads and NT... And it is very very strange for an OS that the key are the multi-tasks... Just like our 95''s, 98''s, 2000''s... That''s why this method is not an crazy or a new idea or a thing "rarely used" as you said. Every serious program with a time critical task to do use threads... This is a "charm" of 32 bits application, it would not cause fear.

And good luck with yours OnIdles, OnTimers, whenclickedons, OnMotherCallings, OnWhateverBe as loop. May this is will be the diference between our games.

The right idea, egrange gived. He are out of any slow event. But, in my opinion, he''s in wrong thread like the most.

Share this post


Link to post
Share on other sites
The point against using threads is that if you don''t have some partice with threads, you will lost your days debugging them.

So, if you are not experienced, avoid using complicated threading scheme, using threads only when necessary, and once you master critical sections and other threads-related enjoyments, you may use and take advantage of them.
Threads are a powerfull tool, but they are treacherous with newbies (seen that too many times...).

IMHO, if you''re not sure where and how to do main loop, rendering etc., stay away from threads untill you gained some more XP and a few levels in programming mastery ;-)

Eric Grange
http://glscene.org

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Fastest possible Delphi game loop? Do NOT use VCL. That is, do not use the Forms unit, TApplication, TForm or any of that. Go raw window creation, message pump and all that. I am doing this with my own application testing my own DirectX wrapper objects. In windowed mode I get over 220fps blitting 640x480x32bit twice per frame. And I know I can get this faster because I am currently using the GDI functions to draw my text.

If you absolutely insist on using the VCL, then the following is the closest you can get to a real game loop.

procedure TForm1.ApplicationIdle(Sender: TObject; var Done: Boolean);
begin
{ Do your processing here. }
ProcessInput;
ProcessAI;
{ If time to render a frame, then do it now. }
Render;
{ Set Done to False so this event is re-triggered constantly
until a message arrives in the queue. }
Done := False;
end;

If you take a look at a CPU meter, it will show 100%, but this is because we are not giving control to the kernel and waiting for messages to arrive. We are busy looping, using all that spare time to do our processing.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Fastest possible Delphi game loop? Do NOT use VCL. That is, do not use the Forms unit, TApplication, TForm or any of that. Go raw window creation, message pump and all that. I am doing this with my own application testing my own DirectX wrapper objects. In windowed mode I get over 220fps blitting 640x480x32bit twice per frame. And I know I can get this faster because I am currently using the GDI functions to draw my text.

If you absolutely insist on using the VCL, then the following is the closest you can get to a real game loop.

procedure TForm1.ApplicationIdle(Sender: TObject; var Done: Boolean);
begin
{ Do your processing here. }
ProcessInput;
ProcessAI;
{ If time to render a frame, then do it now. }
Render;
{ Set Done to False so this event is re-triggered constantly
until a message arrives in the queue. }
Done := False;
end;

If you take a look at a CPU meter, it will show 100%, but this is because we are not giving control to the kernel and waiting for messages to arrive. We are busy looping, using all that spare time to do our processing.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Sorry for the dual post before. I found that this message board does not like apostrophes in the user name. Damned VB script.

To add to my previous comments:

- You do not need to use threads. Most commercial games do not use threads. Threads were introduced into Quake3: Arena very late in its development simply to try to take advantage of SMP (symmetric multi-processing). Age Of Empires 2 does not use threads. The only reason I believe to use threads is if you are implementing DirectPlay. In this case, you need a small thread to receive incoming messages.

- You do NOT need to call Application.ProcessMessages (if you are still using the VCL, that is). This is inviting trouble if you are using event handlers elsewhere. The messages waiting in the message queue will get processed when you return from the OnIdle event handler (or your timer event handler if you are so vain as to use a timer) anyway, so don''t tempt fate.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Hey... I''m rather interested in one of the last posts here -

*Anonymous* Could you be so kind to post an example of non-VCL Delphi? (Preferably a short app that displays a full-screen DirectDraw Surface with a little message, and then waits til [Escape] is pressed.)

Thanks if you do. I never even considered the existence of non-VCL programming (in Delphi and the like) - so I''d like to see it in action, and have some toy-program to experiment with.

Henri, A-Lore

Share this post


Link to post
Share on other sites
Bravo ! Finally someone wrote something good .

To say it once again, if you really want speed, you should forget about the VCL and so on.
And don''t you think getting the whole source code at once is to easy ? The first step is to take a look at the functions
RegisterClassEx and CreateWindowEx. If you managed to create a Window without the VCL you can start using DirectX.

PS : And Henri ... you would have gotten the source anyway, don''t be impatient .

[ Ampaze | www.crazyentertainment.net ]

Share this post


Link to post
Share on other sites
To L-Tryosine:

Sorry, I DID understand everything you said (also I did EXACTLY THE SAME THING before), but my message was unclear due to my lack of english =(

Explaining (again) how using several additional threads can block your main thread:
there''s almost NO WAY to not to use VCL. If you use Win32 API for making forms and such (as said some of our speed lovers) - then why use Delphi at all?! Just get a copy of "our great" Microsoft Visual C++ 6.0 and do as much API as u want with great speed and all. Most of us use Delphi because it has potential and speed in interface creation. My point here is - You WILL and You MUST use VCL no matter where or how.
Ok, so we DO use VCL now. Let''s say you want to create an additional thread to render images. You''ll be calling rendering routines from there most of the time which, of course, are executed in main thread. This makes the same effect as infinite loop in main thread which DOES NOT process messages and anything else but it''s "internal" code (renderings). Also, you WILL call some VCL routines from another thread which is made for "unit movement" so you can be 100% sure that you''ll get main thread totally busy.
About threads and CPU: I just ran Task Manager of my NT5, it showed me 234 threads open. These threads are open, but most of them are suspended or, at least, call ProcessMessages / HandleMessage often. You see, I made a small experiment - opened 3 additional threads, doing some useless stuff there (like sorting arrays and doing some other processing) and one stuff just fills the screen and puts the FPS rate. Guess what I got?! 38 FPS! Nice, isn''t it? You get slow speed even theoretically do nothing (actually you do a lot of processings in other threads).

If I''m unclear again, sorry - my english is no good =(
(Come''n! I''m kinda Ukrainian!)


- Arcane Lifepower -

"Although the world would call me free
Each day the more her slave am I
For in her very way to be
There''s I don''t know what, I don''t know why"

Share this post


Link to post
Share on other sites
quote:

If you use Win32 API for making forms and such (as said some of our speed lovers) - then why use Delphi at all?! Just get a copy of "our great" Microsoft Visual C++ 6.0 and do as much API as u want with great speed and all. Most of us use Delphi because it has potential and speed in interface creation.



"We" don''t use Win32 API to make forms ! The only thing I do is to create a window, because DirectDraw needs a handle to a window. And my window is in no way comparable to a TForm.
In reality its just a black rectangle with no captionbar etc.
And I use Delphi because it has a great language syntax, and C is just a pain to write in
Another thing : What has Delphis "potential and speed in interface creation" to do with the VCL ? The VCL is just one part of Delphi, Delphi offers more !


[ Ampaze | www.crazyentertainment.net ]

Share this post


Link to post
Share on other sites
Before I have to change my nick to "Thread-boy", let''s forget thread for a little.

The recent given idea to build the game with no VCL, is interesting. Although, in my first see, I was not capable to find from where the gain of speed comes in this method, except in the load of the game (VCL loads slow, sure)... But, I can be wrong. So, doubts come in my mind. Ok, I know how to do it, I alredy see zilions of examples... But, the use of directX in this way is new for me, mainly using the DelphiX, because it uses the VCL, and the VCL units (Classes, System, Controls) are declared and used too, so we can even say that it is a part of VCL...
The autor of this idea says "my own DirectX wrapper objects", but did not given much details...

Someone could clear my mind about it? Thanks.

To LifePower:
I think I have finded the point of divergence between us: You said "You''ll be calling rendering routines from there most of the time which, of course, are executed in main thread."...
No, there''s no render routine, the render routine IS the new thread...

About the language, the english is a problem to me too. For example I''m writing this text with a dictionary opened on my side...

Share this post


Link to post
Share on other sites
Hello Thread-boy

well when you decide to not use the VCL, it''s obvious that DelphiX won''t get you far. Here you have to do everything yourself. This starts by creating the DirectDraw7-object (you don''t know what that is do you ?), goes over to surface creation and so on. In short : You loose the comfort DelphiX gives you but for me I like it to have full control.
If you want to start DirectX-Programming you should start with the DX-SDK. Another thing is that I am working on a tutorial series covering non-component DirectX-Programming (but that stays under us )

So far for this.

[ Ampaze | www.crazyentertainment.net ]

Share this post


Link to post
Share on other sites