Game Development Community

Locking a framerate FPS Question

by Andrew Whittle · in Torque Game Builder · 01/22/2009 (1:18 am) · 9 replies

Hi All,

This may be a stupid question but I will ask it in two parts. My game is currently starting at 300 FPS which is a little silly. I would like it to be about 35.

1) Does the FPS have a direct relation to the collision callbacks? By this I mean if it is running at 300 FPS is it calling the callback more times then when it is running at 30 FPS?

2) Is there a way to limit the FPS so that it does not go above lets say 35? My game has a simulation aspect so I would like more control over the clocking of it. When I run it on two different machines I often get different results even though they should be the same.

Thanks

#1
03/24/2010 (3:05 am)
Hi, well, I have a similar problem. I need to control (lock) FPS around 30 - 50, as when it gets under 30 on some computers, it causes different results in gameplay, e.g. some objects get stuck, when they normally don't etc. This is really weird, maybe it's caused by "scheduling" functions, as the proc is "overloaded" and thus unable to perform all tasks on time.

Any help, please?

Thank you.
#2
03/24/2010 (3:16 am)
The "onUpdate" functions get called at regular intervals, specifically at 32 millisecond intervals. If I remember correctly, if 64 milliseconds passes, it will call the function twice.

Another way I sometimes handle this is to to keep track of the elapsed time (delta time) by using getSimTime() and storing the last time since the simulation function was called in a state variable. If your simulation needs to "tick" at 50 millisecond intervals, you can step over the delta time, processing as many times as needed. Make sure you keep a remainder to carry over to the next time the simulation is called.

If you ever get the pro version, it's very, very easy to build a simulation in C++ and expose it to the scripting side (I'm working on a tutorial that covers this if I ever get some time to wrap it up!). In my opinion, this is clean than the scripts.

If you ened specifics, just let me know!
#3
03/24/2010 (3:47 am)
Thank you very much for your fast answer and excuse my english :).

Well, I hope I will need to get Pro in 3 months at the latest. But until then, I need to be able to control right timing and sequence of some events via scripts.

As I'm working on small logical game, I don't need to handle any of game logic in (onUpdate OR onUpdateSceneTick) function, because every time some event occurs, I know what to call next. So I'am using object callbacks a lot for this.

At my first attempt to make logical game, I tried to have whole logic in "onUpdateSceneTIck" function, which was called every 32ms, it mostly, but not completely, helped objects from getting stuck(ed), but it slows performance really badly.

Right now I am using "tickCounter" variable to get information about elapsed time from game start. So what you are proposing is, to get rid of schedule functions (calling functions with some delays). Instead of that store future "function calls" in some kind of event queue and call them from main loop "onUpdateSceneTick" when their time "comes" :) - that could be done thanks to elapsed time counter.

Did I get it? If yes, is this really different from schedules? If not, I'm really sorry, but would appreciate deeper explanation, maybe with some kind of example.
#4
03/24/2010 (1:49 pm)
I still use schedules, but something like this (which you may already be doing):

// Put this code somewhere in a function you call early in your program.
...
$lastSimTime = getSimTime();
runSimulation();
...

// Simulation
function runSimulation()
{
  %currTime = getSimTime();
  %deltaTime = $lastSimTime - %currTime;
  $lastSimTime = %currTime;

  // Process what needs to happen here...

  $simulationTimer = schedule( 50, 0, runSimulation );
}

Depending upon how much you are doing, this can really slow down your game. If you can base your game off of events (like you are doing now), it's a whole lot easier on the system.
#5
03/24/2010 (6:25 pm)
Thank your for the script. Nevertheless, to be honest, I don't understand the advantage of your script over "onUpdate"/"onUpdateSceneTick" and how can this help to control game smoothness better. As I wrote previously, I suspect SCHEDULE calling cause me problems, as its results are different on computers, where FPS gets under around 20 and its always gets worse (occur more often) as FPS gets lower.


Here is part of code, where I have problems with:

function destroyMarked()
{
...

 for(%nrX=1;%nrX<=$TMPMAPSIZEX;%nrX++)
 {

   for(%nrY=1;%nrY<=$TMPMAPSIZEY;%nrY++)
   {

     if (isObject($lettersIngame[%nrX, %nrY]))
     {

       if ($lettersIngame[%nrX, %nrY].isMarked && isLegal(%nrX, %nrY))
       {

         ...

         //Call function which schedule object deletion
         $lettersIngame[%nrX, %nrY].clearAndRemove();

					
         for(%y=%nrY+1;%y<=$TMPMAPSIZEY_BUFFER;%y++)
         {
	   
           if (isObject($lettersIngame[%nrX, %y]))
           {
	   
             //Schedule movement control for objects above this one
             $lettersIngame[%nrX, %y].schedule(400, checkMove);
	   
           }
         }			
       }
     }
   }
 }

 ...
}


This function is called, when other function returns information, that objects are Marked, so they have to be deleted. Important parts are commented, both of these functions are specified below.


function letterClass::clearAndRemove(%this)
{
...

 %this.fadeOut();

 //Deletes object after 350ms
 %this.schedule(350, SafeDelete);

 %this.isDeleting = true;

...
}

function letterClass::checkMove(%this)
{
  %tmpX = %this.xArrayPos;
  %tmpY = %this.yArrayPos;
	
    for (%nrY=%tmpY-1;%nrY > 0 ;%nrY--)
    {
      
      //Check lowest free position to move object to
      if(!isObject($lettersIngame[%tmpX, %nrY]))
      {
        %tmpSpaceCount++;
      }
      else
      {
        break;
      }
    }	
		
    if (%tmpSpaceCount != 0)
    {
      $lettersIngame[%tmpX, %tmpY-%tmpSpaceCount] = %this;
      $lettersIngame[%tmpX, %tmpY-%tmpSpaceCount].yArrayPos = %tmpY-%tmpSpaceCount;
	
      %tmpX2 = %this.xArrayPos;
      %tmpY2 = %this.yArrayPos;
      %xWorldPos = $FIRST_LETTER_POS_X + (%tmpX2-1) * $LETTER_SIZE;
      %yWorldPos = $FIRST_LETTER_POS_Y - (%tmpY2-1) * $LETTER_SIZE;
			
      %this.isMoving = true;

      //Moves object towards lowest free position
      %this.schedule($moveDelayCounter[%tmpX] * 100, "moveTo", %xWorldPos, %yWorldPos, $SPEED_FALLING, true, true);		
			
      $lettersIngame[%tmpX, %tmpY] = 0;
					
      }
}

So, whole script works perfectly fine.
BUT on some computers, where I get FPS under around 20 (e.g. on my 1st generation MacBook Air), I presume, that the MoveTo function isn't SOMETIMES called at time, as %tmpSpaceCount variable equals ZERO, because no object underneath is deleted yet. This causes, that object got stuck and doesn't fall as normally does.

Order of functions calling seems to be ok. "checkMove" function is called (scheduled at 400) after at least one object under is deleted by function "clearAndRemove" (scheduled at 350). Furthermore, setting schedule for deleting object is prior to scheduling of moving for object above it. I tried to increase the ms difference from 400 - 350 = 50ms, to 100ms or more, but didn't notice any improvements.

So does lock up of FPS at e.g. 30ms help? Is it even possible? Am I doing something wrong?

Again, I am maybe completely missing the point. :)
#6
03/24/2010 (11:09 pm)
I'm following you much better!

I would be wary of the line "$lettersIngame[%nrX, %y].schedule(400, checkMove);". Here's my thinking (based upon a few assumptions):

Let's pretend both [1,1] and [1,2] are marked. You'll first come across [1,1] and schedule "checkMove" on [1,2], [1,3], and so on. Then you come across [1,2] and schedule "checkMove" on [1,3], [1,4] and so on. The tile at [1,2] will be deleted 350 milliseconds later, canceling its scheduled call to "checkMove". But [1,4], [1,5], and so on will be calling "checkMove" multiple times.

I can't guarantee that this will cause problems without stepping through all of your code, but it triggers a flag in my brain.

Even if you call "destroyMarked" after a single tile is marked, the user could still click a second tile in less than 400 milliseconds.

You can test this quickly by trying to remove two tiles that are in the same column. If the bug I described doesn't come up, let me know and I can take another look.
#7
03/26/2010 (6:54 am)
Again thanks for your fast respond.

You are right, indeed. Thanks to your advice, I added check to call "ChekMove" only once on every object above deleted one. But this really didn't solve my problem, as the problem is opposite.
By opposite I mean, that it still seems to be connected with low FPS, concretely, that when FPS is under 25, I assume, that sometimes "CheckMove" is called prior to "SafeDelete", even there is 50ms lead for "SafeDelete".

When is FPS over 25, this never happens :(. So my question is, does engine 100% ensure, that order of functions is done by their scheduling order (set by %delay param) regardless of FPS or processor performance?
#8
03/26/2010 (1:52 pm)
Events are sorted by time and are key in order. Also, simulation time (used by the scheduler) doesn't pass while your scripts are executing, so there is no problem with the speed at which the scripts run either.

Something to look out for is the use of "safeDelete". I think I have another scenario for you.

I can't help to think that there's a better way to handle all of this.

When I have a large array of objects, I don't like the objects to handle much. Your "checkMove" function has individual letter tiles handling the movement of the whole array. It seems like you could just call this once at the end of your "destroyMarked" function.

It might also be better to keep an array of booleans to keep track of when an object is no longer there. Your "checkMove" function could compare against the array instead of the object. The "clearAndRemove" could update that array at the same time that the "safeDelete" is called.

(Hope that wasn't too long and made since!)
#9
03/28/2010 (7:08 am)
Well, that's it. Thank you very much for your help. Array of booleans that keep track of object existence was the kind of help, I was looking for :).

About "checkMove", function called by each individual letter object. I didn't decide yet, what to do with this, as in my previous attempt to make logical game, I had entire logic handled in loop "onSceneUpdateTick", which was more performance demanding. On the other hand, control was much better. What you are proposing is just another 2 for cycles for whole array, with "chechMove" function inside. Why I'm not sure, if it's good idea is, that when ANY event happens in game, I know precisely, what to do next, concretely in this case, where to move which letter. So that's why call this function on every letter, where I know, that it does need to move somewhere down. Maybe I should call this function "moveMeDown" instead of "checkMove". :)

But because there is still some kind of bug, that occur really rarely, but occur and it's again object stuck, maybe there is really need for some other change in a way of handling letters movements.


You made my day :), thanks again.