#71566 - deltree - Mon Feb 13, 2006 2:25 pm
hi,
I'm trying to create a shoot em up, but I have a few problems with speed:
when I shoot, the more bullet and missile there are on the screen, the slower the game is, because it multiply the collisions test and the move of the bullets.
The fewer enemies, the quicker is is, on the opposite.
so, my question: how to remain at constant speed? creating artificial pauses, when an enemy die?
shorting the pause when more bullets are shot?
for now, here's what I do: when the bullets are not shot , I only put them in a part of the screen where you can't see them. same thing with dead enemies. so the game continue at constant speed.
should I delete them, and recreate them when needed?
#71572 - tepples - Mon Feb 13, 2006 2:41 pm
Are you sorting your ships and bullets by x or y value and only comparing those that are close to each other?
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#71576 - deltree - Mon Feb 13, 2006 3:19 pm
I make the hit test with every bullets and every enemy.
-64 hit test (8 enemy+8 bullets)
- 16 moves(idem)
-8 hit test(enemy+plane)
-1 move (plane)
I know it's wrong, and I can optimize it a lot, but still, it's not my question for now.
I know I'll have to optimize hit test, but for now, the global speed is correct, even with all those hittests.
I wanted to know how to keep the game speed constant.
#71634 - tepples - Mon Feb 13, 2006 8:44 pm
To keep the game speed constant, you'll need to install a vblank interrupt service routines that notifies the main thread as to how many vblanks have taken place. (There are roughly 60 vblanks in a second.) Then run your game logic every 1 vblank, every 2 vblanks, or every 3 vblanks.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#71821 - deltree - Tue Feb 14, 2006 6:32 pm
For now, I'm running the game logic outside the vblank, in the main loop.
with All the tests and move I need to do, I think the vblank interrupt will not be quick enough to move all the sprites in a decent time, will it ?
if I understood well, the vblank function will execute the code 60 times per seconds, when the "while" main loop will execute your code at a very much higher frequency, (the main CPU frequency) Am I right?
also, what is the smarter solution for bullets: recreate the sprite when shot, and delete it when it's out of the screen?
#71853 - Palamon - Tue Feb 14, 2006 10:10 pm
I think what tepples meant was :
Instead of having your main loop pause at the end for a fixed amount of time
like with some really large for loops and such.
So for small amount of objects to process, you don't see a difference
ie:
do main game loop (which takes say 0.01 sec per object)
pause for 1 sec. (or what ever 100,000 increments of a for loop take)
do main game loop again
so for 10 objects, it will take 1.1 sec
and for 15 objects, 1.15 sec
not much of a difference
but when you get to 100 objects, it takes 2 sec, double the time
So as your main game loop takes longer, the fixed pause doesn't shorten it's pause to compensate
by setting a counter to count the vblanks, and have a vblank interupt to increment it, you can time your main game loops like so
while(1)
{
reset vblank counter to zero
do main game loop functions
while vblank < 60 {}
}//end of main game loop
this way, if your main game loop stuff takes 2 vblanks, (ie 10 objects)
the pause waits for 58 vblanks
so the total game loop time is 60 vblanks
if your main game loop stuff takes 40 vblanks, (like 50 - 100) objects)
the pause waits for 20 vblanks
so the total game loop time is still 60 vblanks
and if your main game loop takes over 60 vblanks, it doesn't pause at all, and then you will notice some slow down.
I hope this makes it a bit clearer, at least in theory anyways.
btw, I haven't quite mastered this technique yet though, I still have a few problems getting it to work on the emulator, but I think it's because I was using a timer interupt instead of vblank.
#71855 - tepples - Tue Feb 14, 2006 10:13 pm
deltree wrote: |
For now, I'm running the game logic outside the vblank, in the main loop. |
True, but if your main code takes longer than about 200,000 cycles, it'll overflow into the vblank, and there will be slowdown.
Quote: |
with All the tests and move I need to do, I think the vblank interrupt will not be quick enough to move all the sprites in a decent time, will it ? |
If you build up a list of copies to OAM and VRAM during draw time, you can then perform that list during vblank time. Every single NES game did this, and so do most GBA games.
Quote: |
if I understood well, the vblank function will execute the code 60 times per seconds, when the "while" main loop will execute your code at a very much higher frequency, (the main CPU frequency) Am I right? |
Yes.
Quote: |
also, what is the smarter solution for bullets: recreate the sprite when shot, and delete it when it's out of the screen? |
Yes, but the details depend on your architecture so far. I still maintain that sorting your bullets by x or y coordinate is likely to open up huge speedups for your collision search algorithms.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#71856 - Quirky - Tue Feb 14, 2006 10:13 pm
You use it like a metronome to check how many ticks go by or wait until the next tick. Here is my attempt to explain it:
Code: |
#define FRAME_RATE 2
volatile int frames = 0;
void
vblank_handler()
{
frames++;
}
int
main()
{
while(1)
{
do_stuff();
while(frames < FRAME_RATE) {
VBlankIntrWait();
}
frames = 0
}
}
|
So there your vblank routine does not much, just lets us know in the main thread that it has happened. With that code, if your logic takes too long, then you don't wait for as many vblanks, if it takes less time then you do wait for vblanks and everything runs at a constant rate. The worst that can happen is your logic takes waaaay too long, but then that doesn't have a solution with the vblank.
#71935 - deltree - Wed Feb 15, 2006 12:48 pm
ok, I understand the vblank trick now.
there's something I'm still wondering about:
If I need to sort the array of enemy position, it's quite a long procedure.
will I need to sort the enemy array every loop? I wonder if it's really shorter than doing all the collision detection...
how to do the sorting of the array quickly and properly?[/b]
#71948 - keldon - Wed Feb 15, 2006 2:57 pm
Merge sort is good, however I think that for certain amounts of elements one of the other algorithms are good as merge sort is always N log2 N
Also you can partition your objects by sectors; i.e. dividing the screen into 8/16 sectors where some objects belong to both.
#71977 - waruwaru - Wed Feb 15, 2006 8:03 pm
deltree wrote: |
will I need to sort the enemy array every loop? I wonder if it's really shorter than doing all the collision detection...[/b] |
After you sort your array once, whenever you add/remove/move an enemy, you can try to keep the array sorted so you don't have to re-sort the entire array. For example, if you have an array with 10 enemies, and it's sorted already. When you move enemy 5 for a small distance, then you probably only need to check against enemy 4 and 6 (and other nearby enemies). If you move a larger distance, then you can sort enemy 1-5 or 5-10. You can even keep 2 arrays, one sorted base on X coord and another on Y coord, that way if your bullets fly horizontally only, it's probably better to check against the array sorted base on X coords. Depending how your enemy moves, you can implement different algorithms. Run some tests with different methods and find the fastest one.