Performance Optimization on GP2X - Code Review Needed

Previous topic - Next topic

François Vanzeveren

Hello,

I have started to code a mini-game designed for the GP2X-F200 and facing some performance issues. I beleive this is because I am new on GLBasic AND game programming.
Currently, bombs are just moving on the screen and bouncing against the borders. With 12 or more bombs on the screen moving simultaneously, performance is decreasing sharply.
In the code, I tried to appy "fixed point" calculation instead of "floating point" to improve performance (as the GP2X does not have a floating point unit), but I feel that the way i applied it in GLBasic might be wrong.

Therefore, I would really appreciate if some more experienced game programmers could review my code and explain me what I am doing wrong.

PS: another problem is the  display of png images on the GP2X: the quality is poor compared to a "windows" build

Here is the whole projet in its latest state: bombsorting_build2008042001.rar - 0.56MB

Thanks a lot to those you will help me to improve my skills and the project.

François

AndyH

Not sure if these things will help a great deal, but worth looking into if you're still having problems finding ways to keep the speed.

If you look in the samples folder that comes with GLBasic, you'll find a QSIN and QCOS function that does faster calculations than the normal COS/SIN.

You could also ensure you redraw as little as possible, eg: use LOADBMP to load in the game screen and then only add in your bombs on top.

Not sure if you are using your sin tables all the time to calculate the movement or not, but if you are then try working out the DX and DY offset at the start only and when you want to change direction, then just INC x,dx and INC y,dy... you could always do if X>320 or X<0 then dx=-dx to change direction (do the same for DY).

You could work out your average FPS while the game is running and use a multiplier factor to adjust the game speed eg:  INC x, dx * fpsfactor --- so that X moves in larger steps to keep the impression of the speed, with the trade off of not moving as smoothly.

Sure others will post some suggestions too :)

Quentin

you don't have to use LOADBMP within the game loop, just load the picture one time e.g. at start of sub Play()

If you want to delete an array you don't have to use FOREACH .. NEXT. Use DIM gBombs[0] instead.

I'm not sure if it make sense to store precalculated values for SIN etc.  I made some tests some time ago and the usage of SIN/COS within the loops was always faster then using precalc. values in arrays. Meanwhile Gernot made some changes of the internal handling of arrays so it might be worth a look again now ;)

There are four ANIMCOLL statements for each bomp. Is this really necessary? Perhaps you can save some of them.

AndyH

Quote from: Quentinyou don't have to use LOADBMP within the game loop, just load the picture one time e.g. at start of sub Play()
Yes, that is what I was meaning, but important to state in case it is used in a loop.

On the subject of arrays, I also find that DIMDEL and DIMPUSH work really well for moderately sized arrays when you just want to manage a list where some elements die after a time (eg: particles) and others need to be introduced.  The next best thing to linked lists, they seem pretty fast (at least for me on Windows + PocketPC).

François Vanzeveren

thank you for  your comments so far...
QuoteIf you look in the samples folder that comes with GLBasic, you'll find a QSIN and QCOS function that does faster calculations than the normal COS/SIN.
QuoteI'm not sure if it make sense to store precalculated values for SIN etc.  I made some tests some time ago and the usage of SIN/COS within the loops was always faster then using precalc. values in arrays.
Ok, thanks for the tips. It will make the code easier, and combined with the newt tips, should have a positive impact on performance.
QuoteNot sure if you are using your sin tables all the time to calculate the movement or not, but if you are then try working out the DX and DY offset at the start only and when you want to change direction, then just INC x,dx and INC y,dy... you could always do if X>320 or X<0 then dx=-dx to change direction (do the same for DY).
I think you spot a good point! dx and dy should indeed be constant as long as there is no collision with the border. I will adapt my code!
QuoteYou could also ensure you redraw as little as possible, eg: use LOADBMP to load in the game screen and then only add in your bombs on top.
Quoteyou don't have to use LOADBMP within the game loop, just load the picture one time e.g. at start of sub Play()
Code (glbasic) Select
LOADBMP "resources/home.png";was indeed misplaced, but has no effect when playing the game. It only affects the drawing of the main manu; So, this does not explain the low performance.
QuoteThere are four ANIMCOLL statements for each bomp. Is this really necessary? Perhaps you can save some of them.
Unfortunatelly, yes as I need to check collision with all borders.

Now, let's go back to work! ;)

PS: btw, any clue on how to improve the display of the sprites?

François Vanzeveren

Ok,

I first adapt the code to compute dX and dY only when necessary (i.e. after a collision) and with QCOS/QSIN, but this did not improve performance.
Then I slightly adapt the code to check the collision and this had a positive impact on performance: now, performance issue appears at around 18 bombs on the screen (instead of around 12).

The latest version of the project is available here: bombsorting_build2008042004.rar - 0.36MB

Of course, i am still open to any advice for improvements.

Thank you very much for your help so far

François

Quoteyou could always do if X>320 or X<0 then dx=-dx to change direction (do the same for DY).
This would definitely save the ANIMCOLL and improve performance... but in the next version, the bombs will bounce on the black and green boxes as well --> using pictures as masks and ANIMCOLL is easier than playing with all coordinate combinations... But I think that when I will consider the collisions between bombs... this will become unavoidable!

AndyH

There is a BOXCOLL command which may be better (you could use masks in sprites rather than anim's).  I'd avoid the pixel perfect collision tests unless you absolutely need it.

Another way you could look at this is perhaps start from a simple application to display bombs and do nothing else.  Work out how many you can get on screen moving (in a simple way) before you notice the slow down.  I haven't got a GP2X (yet) but when I was testing on the PPC which I believe is similar performance wise, I was able to get over 100 32x32 sprites before any noticeable slow down.  Hopefully this will be a lot more than 18 bombs.  You could then work backwards through your code disabling parts to see what helps or measure how quick certain sections take to run using GETTIMERALL().

Just taken a look at your bombs-20px.png - this is using an alpha channel, while nicer is going to be slower due to rendering in software mode.  If you put this to use a solid colour for transparency instead (RGB(255,0,128)) you may find an improvement.  As your background is prominintly light coloured, you could antialias your bomb edges to a mid-grey/white background and you'll probably not notice the lack of blended edges at the speed they generally move?

There are bugs in the following (some bombs get stuck because of the co-ordinates I've hastily put together and the size of bombs are not taken into account) but how many bombs can you display before it slows down?

Code (glbasic) Select
// --------------------------------- //
// Project: Bomb Sorting2
// Start: Sunday, April 20, 2008
// IDE Version: 5.235


TYPE tBomb
x;y
dx;dy
ENDTYPE

GLOBAL bombList[] AS tBomb

SETSCREEN 320,240,0
LIMITFPS 60

// start
LOADBMP "resources/background.png"

LOADANIM "resources/bombs-20px.png", 0, 20, 20

GLOBAL gRunning = TRUE
GLOBAL gCounter = 0

WHILE gRunning

ProcessBombs()

INC gCounter,1
IF gCounter > 60
CreateBomb(RND(280)+19, RND(200)+19)
gCounter = 0
ENDIF

PRINT LEN(bombList[]), 0,0

SHOWSCREEN

// put in something to set gRunning = false when you want to quit out
WEND



FUNCTION ProcessBombs:
LOCAL b AS tBomb

// nb 20 modifier for size of bomb sprite
FOREACH b IN bombList[]
INC b.x, b.dx
INC b.y, b.dy
IF b.x > 300-20 OR b.x < 19 THEN b.dx=-b.dx
IF b.y > 220-20 OR b.y < 19 THEN b.dy=-b.dy

// check for boxed areas
IF b.y > 68 AND (b.x < 102 OR b.x > 219) AND b.dy > 0 THEN b.dy = -b.dy
IF b.y < 170 AND (b.x < 102 OR b.x > 219) AND b.dy < 0 THEN b.dy = -b.dy

IF b.x < 102 AND b.y > 68 AND b.y < 170 AND b.dx < 0 THEN b.dx = -b.dx
IF b.x > 219 AND b.y > 68 AND b.y < 170 AND b.dx > 0 THEN b.dx = -b.dx

DRAWANIM 0,0, b.x, b.y
NEXT

ENDFUNCTION




FUNCTION CreateBomb: x, y
LOCAL b AS tBomb

b.x = x
b.y = y
b.dx = (RND(40)/10)-2
b.dy = (RND(40)/10)-2

DIMPUSH bombList[], b

ENDFUNCTION

François Vanzeveren

Thank you Andy, this is very interesting.

I will apply your advice asap and go back to this thread to let you know the progress.

Again, thank you for your time ;)

Kitty Hello

It should be in your Home Directory : GLBasic/Samples/Common/QMath.gbas
No?