gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Coding > Timing events for a game

#2102 - headspin - Wed Jan 29, 2003 11:50 am

What do you think is the best way to time events, say like certain tiles in a background need changing at different intervals, or timed pauses between changing graphics.

A for loop with a wait for VBlank during each iteration seems to give different timings in an emulator compared to real hardware.

I could use TIMERx or VCOUNT interrupts too, but I'm not sure the best way to go about timing for multiple events. Any ideas?

#2104 - Splam - Wed Jan 29, 2003 12:00 pm

Have a global GAME TIME which just gets incremented every frame, you can base a lot of stuff from that, like gametime&3 to do something every 4 frames etc. I tend to use something like that for general things (like slowing down background anims) and have local timers for sprite animations if they need them (things like a flying kick in a karate game, you want more frames of the "flying" bit than the actual moves to get to that state).

#2119 - headspin - Wed Jan 29, 2003 9:02 pm

Sorry Splam.. what do you mean exactly? What sort of timing do you use, by frames I guess u mean VBlank? That means it would be screwed up for emu's right? And I don't get Gametime&3... do you mean if (Gametime & 3), which suggests your using bits to represent timings or something.. Please explain!

#2121 - Splam - Wed Jan 29, 2003 9:32 pm

Yes, vblank just does gametimer++ which won't screw up on emus, not sure why you think that?

And yup, if (!(3&gametimer)) so the if only happens every 4th frame using that you can & with different values to get 2 4 8 16 frame waits, you know those binary numbers ;)

Not sure how I can explain it any simpler than that. Every vblank the variable is incremented. You then use it as a global timer for events during the game.

#2125 - headspin - Wed Jan 29, 2003 10:14 pm

Waiting for VBlank using an inturrupt seems to work differently than using a simple function to wait for VCOUNT to hit 160 scan lines, say..

Code:

#define REG_VCOUNT     *(u16*)0x4000006
#define INT_VBLANK 0x0001

void WaitVBlankInterrupt()
{
    REG_IME=0;
    REG_IE|=INT_VBLANK;
    REG_DISPSTAT|=(1<<3);
    REG_IME=1; //enable interrupt
}

void WaitVBlank(void)
{
    while (REG_VCOUNT != 160);
}

void Wait(u16 count)
{
    u16 i;

    for(i=0;i<count;i++) WaitVBlank();
}

void InterruptHandler(void)
{
   u16 temp_reg_if=REG_IF;
 
   REG_IME=0;

   *((u16*)0x03007ff8) = REG_IF;
 
   if(temp_reg_if & INT_VBLANK) { }

   REG_IME=1;
}


Then using:

Wait(100); is different to using WaitVBlankInterrupt(); and then using the interrupt to count the VBlanks.

If you use Wait(100); in an emu like VisualBoy Advance, it will wait a much shorter time than on real hardware... Sorry dude am I making any sense?

#2128 - Splam - Wed Jan 29, 2003 11:03 pm

If your waitforvblank routine isn't happening as often as the Wait(100) then there must be something wrong with your code :( The vblank happens on line 160 every frame same as line 100 happens on every frame and I've never seen any problem with using either on an emu. The only thing I can think is if you call a Wait(100) then do some code then loop back to the wait in a tight loop you'll actually still be on line 100 when the loop goes round again. ie

while (1)
{
Wait(100);
gametimer++;
}

would probably increment gametimer quite a few times every frame.
however doing something like

while (1)
{
Wait(100);
gametimer++;
Wait(101);
}

Would stop that happening.

#2130 - FluBBa - Wed Jan 29, 2003 11:07 pm

But then again...
the REG_VCOUNT stays at 160 for the whole scanline doesn't it?
And if your C compiler makes any efficient code your for loop wont work very good then as when the WaitVBlank is called right after it's finnished the count will still be 160 and return without any waiting.

#2146 - Maddox - Thu Jan 30, 2003 3:56 am

Yeah! You better make you code work. Try this:

Code:

void WaitVBlank(void)
{
    while(REG_VCOUNT == 160);
    while (REG_VCOUNT != 160);
}


I win!
_________________
You probably suck. I hope you're is not a game programmer.

#2163 - slip - Thu Jan 30, 2003 11:28 am

Why not use one of the timers for events?
Each object can have a time watcher variable to watch the global timer (one of the timer registers). Say the frame had to change every x seconds then your variable compares its current value with the new value of the regisiter, you calculate how long it has been taking in factors like timer frequency and overflow.
Thats what I do.

slip

#2172 - Splam - Thu Jan 30, 2003 1:16 pm

@slip
Depends how many different timings you need and if you're using timers for other things (playing samples etc) you would run out of timers very quickly.

#2192 - dragor - Fri Jan 31, 2003 12:38 am

If you do things correctly, you only ever need one timer. Look at the PC, it only has one and you can do everything with it. Let's say I have a timer that goes off every 1 millisecond. I can use that to create a 10 millsecond timer and a one second timer. Like the following:

Code:

time = 0;
ten_millisecond = 0;
one_second = 0;

void timer_0(void) {

  time++;

  if(time % 10 == 0)
    ten_millisecond++;
  if(ten_millisecond % 100 == 0)
    one_second++;
}


Doing something like this you can create any number of times with any resolution by using only one hardware timer.
_________________
Sum Ergo Cogito

#2198 - slip - Fri Jan 31, 2003 2:09 am

I'm only using one timer in my current project, and I control the speed of the background the speed of the player moving and when I get to it the speed of bullets and other animations.

#2199 - JonH - Fri Jan 31, 2003 2:23 am

the way that i do this is :

in an init() (or where you initialise your game)

Code:

//start the timer
REG_TM3CNT = TIME_FREQUENCY_1024 | TIME_ENABLE;
s16 start_time = REG_TM3D;
s16 current_time, diff_time;


then, in the main game loop (right at the top of it)

Code:

// update anims
current_time = REG_TM3D;
diff_time = current_time - start_time;

if(diff_time >= 4000)
{
      diff_time=0;
      start_time=REG_TM3D;

      // change the anim frame here
}


by doing it this way, it checks the timer just once every frame so that your program can do other things instead of pausing the whole processor while the game waits!

thats just how i do it, but i can see that a global timer is a good idea and i will try to use that method in the future.

#2210 - tepples - Fri Jan 31, 2003 4:20 am

dragor wrote:
If you do things correctly, you only ever need one timer. Look at the PC, it only has one

No. The PC has three timers on the motherboard and one on the sound card. The timer on the sound card requests samples from the DMA controller; two of the timers on the motherboard control DRAM refresh and the internal speaker's frequency. But it's true that there's only one timer used for scheduling.

But you generally don't need to use one of the GBA's four timers to time animations on the GBA because you already have a 280896 cycle timer called "vblank". Most real console game loops work by synchronizing each frame of a sprite's animation to a given number of vblanks.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#2212 - slapout - Fri Jan 31, 2003 4:28 am

http://www.thepernproject.com/
Day 5 of the tutorials section has some info on timers.

#2358 - headspin - Sun Feb 02, 2003 12:12 pm

I was undecided as to whether to use interrupt timers or waiting for a VBlank. Seems like people here are tending towards using timers.

I had also thought of a global variable keeping track of time for all events, so I think I might give that a go. It's interesting that so many people use different ways for timing. I thought there would be some sort of standard way for the GBA for the most efficient timing of events.

Waiting for a VBlank still dosn't seem to wait consistent times on an Emulator compared to real hardware. I guess timers are a failsafe way to get the exact timing you require.

#2363 - Splam - Sun Feb 02, 2003 3:03 pm

There is a "standard way" and thats vsync/vblank ;) not waiting for it (like the wait(16) method) but using the vsync interrupt. Thats standard on any hardware that has a vsync, trust me I've been coding a looooong time and have always done it that way and every other professional code I know does it that way. You should be using a vsync to time when screen updating is processed to avoid flicker so adding a gametimer++ to that is the most sensible way. It's there for FREE no need to use a timer to do exactly the same thing, whats the point?

Still not sure why you're having problems with emulators, if it didn't work properly then games would screw up badly.

Anyway, ignore my sagely advice if you wish ;) obviously other people are using timers and thats up to them and yourself to do as you see fit but to me thats something akin to using a mul instruction to multiply by 32.

#2373 - Maddox - Sun Feb 02, 2003 6:37 pm

Yeah. Never heard of a pro using a timer for animation/graphics based timing. Even if you wanted to do stuff INTRAframe you would use hblank ints. It's just natural. It's just what those interrupts are for. Maybe someone could post WHY they use a timer instead of vblank or hblank.
_________________
You probably suck. I hope you're is not a game programmer.

#2389 - JonH - Sun Feb 02, 2003 9:39 pm

purely to annoy the likes of you ;)

Maddox wrote:
You probably suck. I hope your not a game programmer.


err... You definitely suck at grammar. I do hope you're not a professional writer.

#2442 - headspin - Tue Feb 04, 2003 1:23 am

Quote:
There is a "standard way" and thats vsync/vblank ;) not waiting for it (like the wait(16) method) but using the vsync interrupt. Thats standard on any hardware that has a vsync, trust me I've been coding a looooong time and have always done it that way and every other professional code I know does it that way. You should be using a vsync to time when screen updating is processed to avoid flicker so adding a gametimer++ to that is the most sensible way. It's there for FREE no need to use a timer to do exactly the same thing, whats the point?


I missed that most obvious point of screen updating during a VBlank so I'm convinced VBlank is the way to go now. Still interesting to see the different ideas on the subject. I spose timers are good for other events that arn't related to updating graphics.

Quote:
Still not sure why you're having problems with emulators, if it didn't work properly then games would screw up badly.


Me neither, I think I might be doing too much processing between the VBlanks so an emulator gives different results. I'm just confused why my game runs faster on an emulator and everyone elses games & demos seem to run the same on hardware as emulators. I'll figure it out one day, just having a break from programming at the moment.

Quote:
Anyway, ignore my sagely advice if you wish ;) obviously other people are using timers and thats up to them and yourself to do as you see fit but to me thats something akin to using a mul instruction to multiply by 32.


I always appreciate your sagely advice Splam!! ;) And thanks for your input on the subject. :)