Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Game speed

This thread is locked; no one can reply to it. rss feed Print
Game speed
Don Freeman
Member #5,110
October 2004
avatar

Ok...I've read the FAQ and some examples of how to do this...but I still can't find anything that shows what I need.

I want to be able to set a 'speed limit', if you will, for fast computers. I am going to design the logic / render loops so they are optimized for the target computer...but I don't want the faster computers to run faster than the target. In the unused time slice, I would like to yeild to the OS.

So, my question is...how do I implement this into my game?
Also...if the interrupt doesn't change the value of a variable, does it still need to be volatile? I wouldn't think so, since the interrupt doesn't change it, but I want to be correct on this.

I would like something like:

1//////////////////////////////////////////////////////////////////////////////////////////////////
2#include <time.h>
3#include <allegro.h>
4//////////////////////////////////////////////////////////////////////////////////////////////////
5volatile int iFPS = 0; // Actual frames per second.
6int iTargetFPS = 20; // the FPS speed limit.
7int iFPSTimerSpeed = 2; // update the FPS counter this fast.
8int iFPSCounter = 0;
9//////////////////////////////////////////////////////////////////////////////////////////////////
10void FPSTimer( void )
11{
12 iFPS = iFPSCounter * iFPSTimerSpeed;
13 iFPSCounter = 0;
14}
15END_OF_FUNCTION(FPSTimer)
16//////////////////////////////////////////////////////////////////////////////////////////////////
17void InitSYS( void )
18{
19 allegro_init();
20 set_color_depth(32);
21 set_gfx_mode(GFX_DIRECTX_WIN,400,400,0,0);
22 set_color_conversion(COLORCONV_TOTAL);
23 install_timer();
24 install_keyboard();
25 install_mouse();
26} // I know...I should check for return values....I don't care right now.
27//////////////////////////////////////////////////////////////////////////////////////////////////
28int main( void )
29{
30 InitSYS();
31 LOCK_VARIABLE(iFPS);
32 LOCK_FUNCTION(FPSCounter);
33 install_int_ex(FPSTimer,BPS_TO_TIMER(iFPSTimerSpeed));
34 while ( true )
35 {
36 if ( keypressed() )
37 {
38 if ( key[KEY_ESC] )
39 {
40 clear_keybuf();
41 break;
42 }
43 }
44 iFPSCounter++;
45 if ( iFPS >= iTargetFPS )
46 {
47 // Do logic / rendering stuff.
48 }
49 else
50 {
51 // yield to system.
52 }
53 textprintf(screen,font,0,0,makecol(255,255,255),"FPS: %i", iFPS);
54 }
55 return 0;
56}
57END_OF_MAIN()
58//////////////////////////////////////////////////////////////////////////////////////////////////

Edit...corrected the code.

--
"Everyone tells me I should forget about you, you don’t deserve me. They’re right, you don’t deserve me, but I deserve you."
"It’s so simple to be wise. Just think of something stupid to say and then don’t say it."

Rick
Member #3,572
June 2003
avatar

Normally:

1voaltile int iLogic;
2void Timer( void )
3{
4 iLogic++;
5}
6END_OF_FUNCTION(FPSTimer)
7 
8//main loop
9bool bRanLogic=false;
10iLogicCounter = 0;
11while(iLogic > 0 && iLogicCounter < 5)
12{
13 logic();
14 iLogicCounter++;
15 iLogic--;
16 bRanLogic = true;
17}
18if(bRanLogic)
19 draw(); //only need to draw if the logic ran
20else
21 //some sort of yeild, to free up OS, I normally skip this

On very fast computers the logic wouldn't run more than once each time it enters the while loop, which would be the timers time 60 BPS if the norm I think, but on slow computers it could get into an infinit loop. That is why we have iLogicCounter. If we get into a situation where logic() runs for a long time and iLogic keeps getting ++ before it hits iLogic--, then the iLogicCounter will make sure we only do this 5 times before breaking out and showing to the user what we did.

========================================================
Actually I think I'm a tad ugly, but some women disagree, mostly Asians for some reason.

Elverion
Member #6,239
September 2005
avatar

Heres a "better" main loop to consider... It uses the timer (speed_counter is the variable for that), and avoids some wasted processing for faster computers. It could still use some minor tweeks, though (Check Rick's post, for example).

1 Init();
2 
3 // other initialization crap
4 
5 while( !quit )
6 {
7 if (key[KEY_ESC]) {
8 quit=true; }
9
10 bool bLogicUpdate = false;
11
12 while(speed_counter <= 0) {
13 rest(1); }
14
15 while(speed_counter > 0)
16 { // logic "step"
17 // accept input
18 // do some calculations
19 
20 bLogicUpdate = true;
21 --speed_counter;
22 }
23
24 // redraw
25 if( bLogicUpdate == true ) {
26 ScreenSystem->draw_flip(); // <-- this blits to the screen...just my way of doing it.
27 fps++; } // <-- this is a variable i use to keep track of FPS. ignore it.
28 yield_timeslice();
29 }
30
31 return 0;

--
SolarStrike Software - MicroMacro home - Automation software.

Kitty Cat
Member #2,815
October 2002
avatar

Elverion, your bLogicUpdate variable is rather useless there. Since you wait with rest(1) until you have logic to do, bLogicUpdate will always be true before it gets checked. As well, yield_timeslice is unneeded since you rest when you're caught up (and if you yield when you're not caught up, you're just wasting time and causing lost frames).

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Tobias Dammers
Member #2,604
August 2002
avatar

I don't know about the rest of you huys, but I haven't managed to produce smooth animation using allegro timers yet, unless I lock in on the physical screen refresh rate (or a multiple of that).
QueryPerformanceCounter() or gettimeofday() are the way to go, they're cheap, accurate and easy to code. Only fall back on allegro timers if you have to.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Go to: