Optimizing Code
Blitz3D Forums/Blitz3D Beginners Area/Optimizing Code
| ||
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 |
| ||
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 |
| ||
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 ;) |
| ||
Fast 2D collisions can be done using this technique: http://www.blitzbasic.com/codearcs/codearcs.php?code=1065 |
| ||
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. |
| ||
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. |
| ||
For even more speed, use rectoverlap. Super fast ;) |
| ||
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 |
| ||
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 |