Hi community.
Actually, I am programming a kind of engine for my planned games. So I am collecting all hints and ideas of
improving the performance of this engine.
I already head some ideas, how to increase the fps, and want to list them here, and hope, that everyone who knows something about performance improvement, is going to post it here. I guess, many people, especially programmers without much experience, would apreciate it and it would help me and other people, improving their games.
Also I want to say, that I used the Search-function, but couldn't find anything about this theme, just many questions about the performance decreasement of different commands etc.
If anything I'm going to write here is wrong, please tell me and I am going to edit it.
Thanks.
(I didn’t test everything I write here, so some things are just assumptions)
--------
***Basic***
Don't use to many #constants representing DBP-Functions (e.g. '#constant scrw = screen width()', rather save the screen width() into a global)
or DBP-functions like
Object position X() or
screen width(), better save object positions in an array and update the array after moving the object, and save not-changing values like the screen-width in a global-variable.
If it's possible to
split very time-intensive calculations, do that. E.g. if you want to hide objects outside the screen, you could each first round check the first quarter, then the second and so on. With such methods, you can also write functions for loading files like images or models in background, so that the game doesn't pause, but run slowlier a short time.
Use the
Sync-Command. The Sync-rate gives you control over the screen-refresh-rate, so that your program runs with the same speed on every computer. Also the programm just syncs one time each loop, and not more often.
Better use the
Text-command then print. It’s not as easy to use, but mostly it’s faster.
Edit: After some discussion with friends and some tests we decided, that both commands have nearly the same speed, so it doesn't matter, which of them you use.
Always
just do, what’s necessary. Don’t check if the options-button in the menue is clicked, when the game is running.
Save time-intensive functions like sin and cos
in an array at the begin of your program, and use this array instead of calling the functions later in your program.
Don’t use floats, if you can use integers instead, and if you declare an array, which elements always should be 1 or 0, let it be a boolean. That saves memory and performance. Edit: It seems as if the variable-types don't really influent the performance, just the RAM.
Before compiling the finished version,
remove all debugging-operations, which are not neccessary. That may increase the fps for some percent.
Reading is always faster than writing, that's true for files, memblocks, arrays and maybe more. So before you change an array element, it's sometimes better to check first, if the element is different from the value you want it to be.
If you use
for-next-loops with a target-value, which doesn't change,
don't let the target be a function, but a variable. If it is a (User-defined or DBP) Function, the program checks it in each round.
Don't use text-layout-commands like
set text size or
set text font in your loops. They slow down the speed very much, even if you use them only one time to print one letter.
Use the sync-command just as often as neccessary. You don't have to update the screen oftener then about 30 times a second. If you game rund faster then with 30 fps, it will run even faster if you just update the screen 30 times a second.
***Landscape***
The best method of using big landscapes for games, is an
Advanced Terrain, made from a heightmap. They look relistic because of the base- and detail-texture and the good self-shadowing, and it’s hard to see single polygons.
Edit: I call Advanced Terrain the best decision, because they are fast and realistic looking, not because the are the easiest to use.
If you use realtime vertex-manipulation for a terrain-editor, or even if you just use them in games, you should
split them in different terrains (e.g. 4*4) and just edit/show those, which are in screen.
Use
DBP-Fog, it’s kind of realistic and the engine doesn’t have to show all polygons, if you set the max camera range to the fog-distance-value.
If you know the vertex-commands, and how to use them,
decrease the polygon-count of the terrain. If some polygons next to each other have nearly the same gradient, make one polygon out of them.
Don’t use too big heightmaps. The best size is 512*512. It’s
better to stretch the terrain in X- and Z-Direction, then to use a bigger heightmap.
Use more then one terrains and
use LOD for the Polygons and the texture. You could split a 2048^2-heightmap into 8*8 parts and the parts near by the camera should have most details, and the parts far away less polygons and a low-res-texture. It might be hard or much to code, but I guess it speeds up the game a lot, and you can use very big landscapes.
***Objects***
Generally, just use
low-poly-objects in your games, better a high-resolution texture and a low-poly object, then the other way round.
Use
Level-of-detail by loading two meshes (and two textures) for each object, and replacing the high-poly-object with the low-poly one, when the camera is far away enough.
Hide all objects with many polygons, which are not in screen.
***Shaders***
Use just
as many shaders as necessary, because most of them are very bad for the performance, even if they may increase the quality of your game.
Stop shaders, if they are too far away. Why should you bump-map a wall, if the player stands 50 meters away?
***Physics***
Don’t check object collisions, if the objects are to far away from each other to collide. Make an array and save the objects size after loading, and before checking a collision later, check if the object distance is small enough, that a collision would be possible.
You should only
check collisions for those objects, which have to collide, like buildings or characters, but not little things like grass.
If you check the object distance,
don't use the sqrt-function, but square the values, or use vector commands.
***2D (Images, Sprites etc.)***
If your 2D-game is tile-based, just
paste/show the sprites/images inside the screen.
If a
small sprite is under a big one, you don't have to paste/show it. (e.g. a grass-tile under a building)
Just check sprite collisions, if it's possible, that they collide (by comparing distance with sprite-sizes).
If you draw many dots at one time, or use the point-command, write before and after the loop a
lock- and unlock pixels.
--------
***Codes***
**Basic**
- DBP-Functions or variables
REM DBP-Functions or variables
make object cube 1, 100
sync on : sync rate 0
Object_Position_X = object position x(1)
do
yrotate object 1, object angle y(1)+0.1
if controlkey()=1
print "DBP-Function"
for round = 0 to 99999
Xpos = object position x(1)
next round
else
print "Variable"
for round = 0 to 99999
Xpos = object_position_x
next round
endif
set cursor 0,0
print "FPS:",screen fps()
print "X-Position:",Xpos
print "--> Press controlkey to use the DBP-function"
sync
loop
- Splitting of time-intensive calculations
REM Splitting of time-intensive calculations
sync on : sync rate 0
for object = 1 to 250
make object cube object, 10
position object object, rnd(300), rnd(300), rnd(300)
next object
do
set cursor 0,0
print "FPS:",screen fps()
if controlkey()=1
print "Control for: All objects"
for round = 0 to 999
for Object = 1 to 250
inscr = object in screen(Object)
vis = object visible(Object)
if inscr = 1 and vis = 0 then show object Object
if inscr = 0 and vis = 1 then hide object Object
next Object
next round
else
Value = (Value+1) mod 4
start = Value*50+1
Target = (Value+1)*50
print "Control for: Object ",start,"-",target
for round = 0 to 999
for Object = Start to Target
inscr = object in screen(Object)
vis = object visible(Object)
if inscr = 1 and vis = 0 then show object Object
if inscr = 0 and vis = 1 then hide object Object
next object
next round
endif
control camera using arrowkeys 0,1,1
sync
loop
- Using Sync and Sync On
REM Sync-advantages
Pressed as boolean
SyncLoop:
Pressed = 1
sync on
do
cls
print "With Sync:"
print screen fps()
print "--press controlkey to set sync off--"
Number = 0
do
inc Number, 1
if Number > 100 then exit
loop
if controlkey()=0
pressed = 0
else
if pressed = 0 then goto NoSyncLoop
endif
sync
loop
NoSyncLoop:
Pressed = 1
sync off
do
cls
print "Without Sync:"
print screen fps()
print "--press controlkey to set sync on--"
Number = 0
do
inc Number, 1
if Number > 100 then exit
loop
if controlkey()=0
pressed = 0
else
if pressed = 0 then goto SyncLoop
endif
loop
-Functions or Arrays?
REM Sin, cos and tan or array
dim _Sin(359)
dim _Cos(359)
dim _Tan(359)
for angle = 0 to 359
_Sin(angle) = sin(angle)
_Cos(angle) = cos(angle)
_Tan(angle) = tan(angle)
next angle
do
cls
print screen fps()
if controlkey()=1
print "DBP-functions used"
for round = 0 to 99999
s = sin(rnd(359))
c = cos(rnd(359))
t = tan(rnd(359))
next round
else
print "Array used"
for round = 0 to 99999
s = _sin(rnd(359))
c = _cos(rnd(359))
t = _tan(rnd(359))
next round
endif
loop
-Floats or Booleans?
REM Floats or booleans
REM Info: Try it out with both declarisions, one time as float, and one time as boolean, and look for the RAM in Task-manager
REM On my computer, it was 6mb without an array, 12mb with the boolean-array and 15mb with the float-array
REM But the program seems to run with the same speed both times
dim MyArray(999,999) as float
`dim MyArray(999,999) as boolean
do
cls
print screen fps()
loop
-Debugging-operations
REM Debugging-operations
sync on : sync rate 0
for Object = 1 to 250
make object Cube Object, 10
position object Object, rnd(300), rnd(300), rnd(300)
next Object
do
set cursor 0,0
print "FPS:",screen fps()
if controlkey()=1
print "With Debugging"
for Round = 0 to 999
for o = 1 to 250
if object exist(o)
TestVariable = 100
endif
next o
next Round
else
print "Without Debugging"
for Round = 0 to 999
for o = 1 to 250
TestVariable = 100
next o
next Round
endif
control camera using arrowkeys 0,1,1
sync
loop
-Reading and writing
dim Array(99999)
do
cls
print screen fps()
if controlkey()
print "Write"
for round = 0 to 99999
Array(rnd(99999)) = rnd(999)
next round
else
print "Read"
for round = 0 to 99999
Value = Array(rnd(99999))
next round
endif
loop
-For-next target as variable
REM For-Next-Target as variable
set display mode 1024,768,32
do
cls
print screen fps()
if controlkey()=1
print "Slow"
for Round = 0 to 9999
for x = 1 to screen width()
Value = x
next x
next Round
else
print "Fast"
for Round = 0 to 9999
sw = screen width()
for x = 1 to sw
Value = x
next x
next Round
endif
loop
-Text-Layout commands
REM Text-Layout commands
set text font "Arial"
set text size 20
do
cls
print screen fps()
if controlkey()
set text size 16
set text font "Tahoma"
print "Text-size changed"
set text font "Arial"
set text size 20
else
print "Text-size not changed"
endif
loop
-Sync-Limitation
REM Limited Sync-Usage
sync on
sync rate 0
hide mouse
REM Variables
SyncDelay = 1000/30
LastSync = timer()
LastTime = timer()-5
for o = 1 to 1000
make object cube o, 40
position object o, rnd(2000)-1000, rnd(2000)-1000, rnd(2000)
next o
do
fps = Screen_FPS()
ink rgb(192,192,192),0
box 0,0,50,20
ink rgb(0,0,0),0
text 0,0, str$(fps)
if controlkey()
text 0,20, "Slow"
sync
else
text 0,20, "Fast"
if timer() => LastSync + SyncDelay
LastSync = timer()
sync
endif
endif
for o = 1 to 1000
yrotate object o, object angle y(o)+0.1
next o
mmy = mousemovey()
mmx = mousemovex()
xrotate camera 0, camera angle x(0)+ mmy*abs(mmy)/15.0
yrotate camera 0, camera angle y(0)+ mmx*abs(mmx)/15.0
loop
REM You may use this function, if you want. It might be better then 'screen fps()' because you can change the delay (Fps_ChangeDelay).
function Screen_FPS()
if FPS_Initialised = 0
global FPS_Initialised as boolean
FPS_Initialised = 1
global FPS_AddedTime
global FPS_AddedNumber
global FPS_LastTime
global FPS_Value
global FPS_LastChange
global FPS_Debug
global FPS_ChangeDelay = 500
else
inc FPS_AddedTime, timer()-FPS_LastTime
inc FPS_AddedNumber, 1
if timer() => FPS_LastChange + FPS_ChangeDelay
FPS_Value = 1000.0/(FPS_AddedTime/(FPS_AddedNumber*1.0))
FPS_AddedTime = 0
FPS_AddedNumber = 0
FPS_LastChange = timer()
inc FPS_Debug, 1
endif
FPS_LastTime = timer()
endif
endfunction FPS_Value
**Landscape-Codes**
-DBP-Fog and Camera-Range
set display mode 800,600,32
sync on
sync rate 0
FogMode as boolean
FogMode = 0 `if this value is 1, fog will be used, else theres no fog and a big camera range
if FogMode = 1
fog on
fog distance 2000
fog color 128,128,128
set camera range 0, 1, 2250
else
set camera range 0, 1, 15000
endif
for o = 1 to 100
make object sphere o, 100, 30, 30
position object o, rnd(10000), rnd(300), rnd(10000)
next o
make matrix 1, 10000, 10000, 50, 50
randomize matrix 1, 100
update matrix 1
lock pixels
for x = 0 to 512
for y = 0 to 512
g = 150+rnd(105)
b = rnd(g/2)
r = rnd(g/2)
dot x,y, rgb(r,g,b)
next y
next x
unlock pixels
get image 1,0,0,512,512,1
prepare matrix texture 1, 1, 1, 1
do
set cursor 0,0
print screen fps()
print statistic(1)
mmx = mousemovex()
mmy = mousemovey()
yrotate camera 0, camera angle y(0) + (mmx*abs(mmx))/10.0
xrotate camera 0, camera angle x(0) + (mmy*abs(mmy))/10.0
Control()
sync
loop
function Control()
uk = upkey()
dk = downkey()
move camera 0, uk-dk
endfunction
--------
That’s all for now. I hope, that you’ll post more tips or comment mine. Maybe some of them are wrong, or aren’t true in all cases (that’s no question… of course there are always exceptions).
I think, I am going to update the list after reading your posts, so that no one has to read the whole thread, to get to know these things.
Thanks for (hopefully) answering.
Edit: Of course, not all of the tips are my ideas. Some are from other forums, and some may be edited after being in posts from this thread.
Visit the DBPro - Speed up your game-Thread. http://forum.thegamecreators.com/?m=forum_view&t=88661&b=1