Optimizing Code

Blitz3D Forums/Blitz3D Beginners Area/Optimizing Code

Mr. Shen(Posted 2004) [#1]
I've got a question for ya super-duper coders out there. Right now I'm working on a shooter very much like Gradius (2d, handdrawn stuffs) and was wondering about optimizing the code.

Right now, it runs fine on my P4 2.4ghz 512mb Ram system. The thing I'm worried about is that with every pass through the main game loop, it updates movement of all the pieces (bullets, your ship, enemy ships, player information like score and shields) and also then checks collisions to see if any of the enemies have been hit by any of the bullets or your ship. This seems like it's doing too much.

Am I right to be concerned about the code or is this pretty much the only way to do it without "threading" (I read that somewhere)? Any opinions would be super, thanks!

-Alex


BlackD(Posted 2004) [#2]
You can optimise to a certain extent. Elminate any functions that don't need to be checked. For instance:
playermoved=ProcessPlayerInput()
  ;if player moved, return 1, else return 0
enemymoved=ProcessAIResponse()
  ;if enemy moved, return 1, else return 0
If NumBullets > 0 then UpdateBullets()    ;only update bullets if there are actually some there
If PlayerMoved then UpdatePlayer()    ;only update player entities if player moved.
If EnemyMoved then UpdateEnemies()    ;only update enemy entities if they actually moved.
If (numbullets+playermoved+enemymoved) > 0 then
    CheckCollisions()
    UpdateScore()
    End If
       ;only update the score if someone moved or some 
bullets hit something and earned some points. And more 
importantly, only checks collisions if something actually 
happened.

Most of that won't really save you CPU time, but its just a hint to show you how you can skip unnecesary operations. Most time consuming is checking collisions and refreshing all the entity positions if they don't need to be done. Why check if the player collided with any one of 300 (or whatever) entities, if the player didn't move, the enemies didn't move, and there are no bullets?

This example will only save you a couple of hundredths of a second. Its not an answer - more a point in the right direction. :) Most importantly - if nothing in the scene has changed, DON'T UPDATEWORLD. Just RENDERWORLD. You'll save some more cycles there. :)

+BlackD


Ross C(Posted 2004) [#3]
Yeah, actual code is super fast. If it's 2d, the only real speed hit would be actually drawing the images. I remember once i check 40 balls individually against 100 odd bricks. It was pretty quick ;)


big10p(Posted 2004) [#4]
Fast 2D collisions can be done using this technique:
http://www.blitzbasic.com/codearcs/codearcs.php?code=1065


WolRon(Posted 2004) [#5]
If your collisions are pixel-perfect (ImagesCollide), you might be able to shave off a few seconds by performing a box-collision check (ImagesOverlap) first. If that fails, there's no need to perform a pixel-perfect check.

I haven't actually tested this, but it should help.


big10p(Posted 2004) [#6]
Pixel-perfect collisions in Blitz don't seem to be a great deal slower than box collisions so I suspect ImagesCollide does a box check first, internally. Don't know for sure, though.


Ross C(Posted 2004) [#7]
For even more speed, use rectoverlap. Super fast ;)


TomToad(Posted 2004) [#8]
Another speedup would be to avoid redrawing the entire screen each loop. Instead of doing:
UpdatePlayerCoords()
UpdateEnemyCoords()

cls
DrawBlock background,0,0
DrawImage player\image,player\x,player\y
DrawImage enemy\image,enemy\x,enemy\y

Do something like this instead
;assuming player size is 64x64 pixels

DrawBlockRect background,player\x,player\y,64,64
DrawBlockRect background,enemy\x,enemy\y,64,64

UpdatePlayerCoors()
UpdateEnemyCoords()

DrawImage player\image,player\x,player\y
DrawImage enemy\image,enemy\x,enemy,y


Now if you're using a backbuffer, then you need to hold the coordinates for two frames earlier so that you'll write over the correct part of the background
;assuming player size is 64x64 pixels

DrawBlockRect background,oldplayerx,oldplayery,64,64
DrawBlockRect background,oldenemyx,oldenemyy,64,64

oldplayerx = player\x
oldplayery = player\y
oldenemyx = enemy\x
oldenemyy = enemy\y

UpdatePlayerCoors()
UpdateEnemyCoords()

DrawImage player\image,player\x,player\y
DrawImage enemy\image,enemy\x,enemy,y

flip



MSW(Posted 2004) [#9]
The drawing will be the most time consumeing part...followed by the collision detection.

As you are doing a shooter, the design of the game itself can lead to some ways to optimize the collision routine.

as the player shots are most likely traveling from the left to the right, you can construct a grouping routine to define a rectangle of screen space that the player bullets occupy...

for example, something like this:

;start of main loop

Bull_max_X = 0
Bull_max_Y = 0
Bull_min_X = screenwidth
Bull_min_Y = screenhieght

For b.bullet = each bullet

  b\x = b\x + 3

   if b\x > Bull_max_X then Bull_max_X = b\x
   if b\y > bull_max_y then Bull_max_y = b\y
   if b\x > Bull_min_X then Bull_min_X = b\x
   if b\y > bull_min_y then Bull_min_y = b\y

Next


For e.enemy = each enemy

  if e\x > Bull_min_X and e\x < Bull_max_X
    if e\y > bull_min_Y and e\Y < Bull_max_Y

       ;do collisions
    end if
  end if

next



One more thing you may want to consider is to roll your own collision routines and not use the Blitz supplied ones...function calls inside nested loops can be much slower then pure code inside the same loop