FPS/Physics
by Jaybill · in Torque Game Builder · 02/16/2006 (6:39 pm) · 17 replies
I've already been through the forums looking for some info on this, but I'm still kind of stumped.
Is there an obvious way to make a game behave the same on all systems?
I tried adding the following code:
(and several trial and error variations of parameters) but all it does is totally whack out my otherwise working physics setup. I'm using t2d physics called by onUpdateScene as laid out in the platformer tutorial.
Without the above code, when I run at my native resolution fullscreen (1280 x 1024) - I get like 900fps and everything does what it's supposed to do. If I run at lower resolutions, windowed or fullscreen, things move a marked order faster. It's not terrible, but it's not consistant, which is weird.
Am I missing something obvious here? Is there a rock solid way to ensure the thing will behave as close to the same as possible on most machines? I mean, if your machine is slower, obviously the framerate will be lower, but it's affecting the speed at which updates occur, which can't be right.
Any ideas?
Is there an obvious way to make a game behave the same on all systems?
I tried adding the following code:
t2dScene.setScenePhysicsFPSActive(true); t2dScene.setScenePhysicsLimitFPS(1); t2dScene.setScenePhysicsTargetFPS(60); t2dScene.setScenePhysicsMaxIterations(2);
(and several trial and error variations of parameters) but all it does is totally whack out my otherwise working physics setup. I'm using t2d physics called by onUpdateScene as laid out in the platformer tutorial.
Without the above code, when I run at my native resolution fullscreen (1280 x 1024) - I get like 900fps and everything does what it's supposed to do. If I run at lower resolutions, windowed or fullscreen, things move a marked order faster. It's not terrible, but it's not consistant, which is weird.
Am I missing something obvious here? Is there a rock solid way to ensure the thing will behave as close to the same as possible on most machines? I mean, if your machine is slower, obviously the framerate will be lower, but it's affecting the speed at which updates occur, which can't be right.
Any ideas?
About the author
#2
However, you were already on the right track I think with the setScenePhysicsFPSActive calls. I'm guessing that it is whacking out your otherwise-working physics setup because your existing physics setup is tuned to work with your 900fps, and the ScenePhysics is forcing ~60FPS behavior from all things physical.
I had the same problem, where the game looked and played great on my development machine, but when I tried it on other hardware, stuff was faster/slower depending on the FPS. So I switched on setScenePhysicsFPSActive and my dev box was totally whacked out just like you described.
However, it was now consistently whacked out on all hardware; so I re-tuned all the physics so it was back to normal with setScenePhysicsFPSActive, and voila! It was now fine on both my dev box and all other machines I played it on.
As I said this may be totally inapplicable to the platform tutorial, but it sounded like a possibility. Hope it helps.
02/18/2006 (12:43 pm)
I haven't looked at the platform tutorial much, so perhaps this won't be accurate information. However, you were already on the right track I think with the setScenePhysicsFPSActive calls. I'm guessing that it is whacking out your otherwise-working physics setup because your existing physics setup is tuned to work with your 900fps, and the ScenePhysics is forcing ~60FPS behavior from all things physical.
I had the same problem, where the game looked and played great on my development machine, but when I tried it on other hardware, stuff was faster/slower depending on the FPS. So I switched on setScenePhysicsFPSActive and my dev box was totally whacked out just like you described.
However, it was now consistently whacked out on all hardware; so I re-tuned all the physics so it was back to normal with setScenePhysicsFPSActive, and voila! It was now fine on both my dev box and all other machines I played it on.
As I said this may be totally inapplicable to the platform tutorial, but it sounded like a possibility. Hope it helps.
#3
Luke is correct, the "setScenePhysicsFPSActive()" turns on the frame-independance in TGB. You've set the target to be 60-fps which means the simulation will get 60 updates a second as opposed to your previous 900 updates (which is way too much anyway).
Typically, you'd want it to run in the 80-fps or more region although stuff like using rigid-body physics does work better with higher-rates but for standard stuff, this would be fine.
Another problem you're probably having is that it sounds like you're applying forces and stuff in the "onUpdateScene()" which is currently only called each "frame" (therefore frame-dependant) and was designed for doing time-irrelevant game logic and not physics update. There was a post recently that showed how to make this call so that it occurs when the simulation is updated instead.
Also, you're setting "max-interations" to "2" which allows TGB to potentially do two-passes of scene-update checks for every object in the simulation. The higher this number, the more potential work that TGB will have to do. Essentially, it'll time-slice the update interval into the iterations you specify if the FPS goes below the "limit" (as you specify above).
So here's the story ... you activate the scene-physics frame-independance (setScenePhysicsFPSActive) and you set it to 60fps (setScenePhysicsTargetFPS) which means the simulation will get called 60-times a second consistently on all machines. If, for whatever reason, the actual FPS goes below the "limit" (setScenePhysicsLimitFPS), then TGB will time-slice the interval (which'll be greater than 1/60th sec) into the number of "iterations" (setScenePhysicsMaxIterations).
You've set the limit to "1" so if the fps goes below 1-fps (not that useful), it'll split-up the interval and make "2" ( setScenePhysicsMaxIterations(2)) passes. Taking multiple passes means more CPU work but smaller time-intervals for the physics.
Your reference to letting TGB do all the work is still correct, turn-on the frame-independance, set your simulations FPS and it does work. Like any simulation, you should fully understand what typical frame-rate you want to run at. This equates to understanding the number of updates a second that your game needs to run effectively and on machines that can't meet that target, for whatever reason, what to do such as how many sub-update iterations to do to split-up the time-interval.
You should absolutely not do physics-forces updates in "onUpdateScene()" unless you change it to be called other than each frame.
I've been working on some documentation for the physics and collisions and I'm hoping to get that out ASAP.
Hope this helps,
- Melv.
02/19/2006 (5:09 am)
Jaybill,Luke is correct, the "setScenePhysicsFPSActive()" turns on the frame-independance in TGB. You've set the target to be 60-fps which means the simulation will get 60 updates a second as opposed to your previous 900 updates (which is way too much anyway).
Typically, you'd want it to run in the 80-fps or more region although stuff like using rigid-body physics does work better with higher-rates but for standard stuff, this would be fine.
Another problem you're probably having is that it sounds like you're applying forces and stuff in the "onUpdateScene()" which is currently only called each "frame" (therefore frame-dependant) and was designed for doing time-irrelevant game logic and not physics update. There was a post recently that showed how to make this call so that it occurs when the simulation is updated instead.
Also, you're setting "max-interations" to "2" which allows TGB to potentially do two-passes of scene-update checks for every object in the simulation. The higher this number, the more potential work that TGB will have to do. Essentially, it'll time-slice the update interval into the iterations you specify if the FPS goes below the "limit" (as you specify above).
So here's the story ... you activate the scene-physics frame-independance (setScenePhysicsFPSActive) and you set it to 60fps (setScenePhysicsTargetFPS) which means the simulation will get called 60-times a second consistently on all machines. If, for whatever reason, the actual FPS goes below the "limit" (setScenePhysicsLimitFPS), then TGB will time-slice the interval (which'll be greater than 1/60th sec) into the number of "iterations" (setScenePhysicsMaxIterations).
You've set the limit to "1" so if the fps goes below 1-fps (not that useful), it'll split-up the interval and make "2" ( setScenePhysicsMaxIterations(2)) passes. Taking multiple passes means more CPU work but smaller time-intervals for the physics.
Your reference to letting TGB do all the work is still correct, turn-on the frame-independance, set your simulations FPS and it does work. Like any simulation, you should fully understand what typical frame-rate you want to run at. This equates to understanding the number of updates a second that your game needs to run effectively and on machines that can't meet that target, for whatever reason, what to do such as how many sub-update iterations to do to split-up the time-interval.
You should absolutely not do physics-forces updates in "onUpdateScene()" unless you change it to be called other than each frame.
I've been working on some documentation for the physics and collisions and I'm hoping to get that out ASAP.
Hope this helps,
- Melv.
#4
@Melv - Thanks, this does help, a lot. Where would you suggest calling a physics update? Is there an "onUpdateSimulation" or would it be worth it to schedule a function that calls itself on a schedule of once a millisecond or something?
I've also noticed something pretty peculiar in screwing around with this, which is that if I run at 1280x1024, the thing runs slower. If I run at any other resolution fullscreen or not, it works fine. 640x480 windowed runs at the exact same speed as 800x600 with setScenePhysicsTargetFPS turned on. It seems to just be that mode that causes the problem.
02/19/2006 (8:19 am)
@Luke - Thanks, that put me on the right track.@Melv - Thanks, this does help, a lot. Where would you suggest calling a physics update? Is there an "onUpdateSimulation" or would it be worth it to schedule a function that calls itself on a schedule of once a millisecond or something?
I've also noticed something pretty peculiar in screwing around with this, which is that if I run at 1280x1024, the thing runs slower. If I run at any other resolution fullscreen or not, it works fine. 640x480 windowed runs at the exact same speed as 800x600 with setScenePhysicsTargetFPS turned on. It seems to just be that mode that causes the problem.
#5
The second answer is to ensure that the forces you apply take into account the elapsed time, assuming they don't already.
I believe there was a post recently showing you how to ensure this. The problem you're probably getting (without know what type of calls you're making) is that if you're making cummulative force calls such as applying impulses then you'll get a difference of gross force dependant upon the actual frame-rate that will obviously vary from machine to machine but will also fluctuate on the same machine.
Changing the velocity directly won't have such an impact but will change the physics events temporally e.g. objects will changing direction at different times or not consistently.
A regular schedule either using "schedule" or the periodic timer on each object ".setTimerOn()" can help solve this as the call is strictly periodic independant of frame-rate and varies only very slightly due to the event-processing pipeline.
With regards to the "1280x1024" issue; I've not experienced that myself as I consistantly run at that resolution in windowed mode whilst developing. It would be easy to say that it's a graphics-driver issue but the honest truth is, I just don't know. If you make all the objects invisible, they'd still update and everything should pretty much take the approximate same CPU cycles but it would remove alot of the rendering. It would be interesting to see if this made a difference.
- Melv.
02/19/2006 (10:55 am)
Quote:Where would you suggest calling a physics update?Well, there are two answers here. The first is that we should update the "onUpdateScene()" to be called every time the scene is updating. ;) This can mean lots of calls per frame but the name does imply that it's related to the scene-update, not the frame-update.
The second answer is to ensure that the forces you apply take into account the elapsed time, assuming they don't already.
I believe there was a post recently showing you how to ensure this. The problem you're probably getting (without know what type of calls you're making) is that if you're making cummulative force calls such as applying impulses then you'll get a difference of gross force dependant upon the actual frame-rate that will obviously vary from machine to machine but will also fluctuate on the same machine.
Changing the velocity directly won't have such an impact but will change the physics events temporally e.g. objects will changing direction at different times or not consistently.
A regular schedule either using "schedule" or the periodic timer on each object ".setTimerOn()" can help solve this as the call is strictly periodic independant of frame-rate and varies only very slightly due to the event-processing pipeline.
With regards to the "1280x1024" issue; I've not experienced that myself as I consistantly run at that resolution in windowed mode whilst developing. It would be easy to say that it's a graphics-driver issue but the honest truth is, I just don't know. If you make all the objects invisible, they'd still update and everything should pretty much take the approximate same CPU cycles but it would remove alot of the rendering. It would be interesting to see if this made a difference.
- Melv.
#6
When I load a map, I do this:
Then updateLevel does this:
And this works pretty consistantly at every resoultion I tried. (I have not tried a slower machine yet. I suspect it will still work right.) The thing is, I think there may actually be a problem that's not physics or scheduling. Sometimes (as in 1024x1280) the game just runs slower. Everything lands in the right place and updates correctly, it just does so at about 75% of the speed. Annyoing, but whatever, that's at least consistant.
The show stopper is that sometimes, for no reason I can acertain, at the start of a level, the thing will suddenly run like 300% faster than it usually does (again, everything "lands" correctly, so physics is not "wrong" just fast.) for a few seconds. Then it goes back to normal.
There is some strange inconsistancy here and I can't determine if it's something I'm doing wrong or a flaw in the engine. Any ideas what I should try next?
02/22/2006 (8:52 am)
@Melv - reworked my code so that things update once a millisecond rather than in onUpdateScene. Like so:When I load a map, I do this:
t2dScene.setScenePhysicsFPSActive(true); t2dScene.setScenePhysicsTargetFPS(500); ... snip ... $levelLoaded = true; updateLevel();
Then updateLevel does this:
function updateLevel(){
if($levelLoaded){
for (%i = 0; %i < EnemyGroup.getCount(); %i++)
{
updateEnemy(EnemyGroup.getObject(%i));
}
for (%i = 0; %i < VatorGroup.getCount(); %i++)
{
updateVator(VatorGroup.getObject(%i));
}
updateBg();
updatePlayer();
$camera.update();
$runSurface = -1;
schedule($updateInterval,$levelPlayer,"updateLevel"); // $updateInterval is set to 1.
}
}And this works pretty consistantly at every resoultion I tried. (I have not tried a slower machine yet. I suspect it will still work right.) The thing is, I think there may actually be a problem that's not physics or scheduling. Sometimes (as in 1024x1280) the game just runs slower. Everything lands in the right place and updates correctly, it just does so at about 75% of the speed. Annyoing, but whatever, that's at least consistant.
The show stopper is that sometimes, for no reason I can acertain, at the start of a level, the thing will suddenly run like 300% faster than it usually does (again, everything "lands" correctly, so physics is not "wrong" just fast.) for a few seconds. Then it goes back to normal.
There is some strange inconsistancy here and I can't determine if it's something I'm doing wrong or a flaw in the engine. Any ideas what I should try next?
#7
For example, if at the start of your level you load files or have uncached images/audio that cause a processing delay, then everything seems to accelerate for a brief period to catch up to where it should be. I've seen this happen under these circumstances, or even if you alt-tab in and out, or grab the title bar and move the window.
02/22/2006 (5:50 pm)
The 300% faster is, I'm guessing, a burst of speed happening as things try to catch up because of some processing delay. For example, if at the start of your level you load files or have uncached images/audio that cause a processing delay, then everything seems to accelerate for a brief period to catch up to where it should be. I've seen this happen under these circumstances, or even if you alt-tab in and out, or grab the title bar and move the window.
#8
So there isn't really an easy answer to this, is there.
02/22/2006 (6:23 pm)
@Luke - I actually can get it to do that on command if I click on the title bar or alt-tab out as you say.So there isn't really an easy answer to this, is there.
#9
It is a good idea to preload audio where possible and build pauses/loading screens/etc. into the flow where large sets of files are loaded to minimize the effect.
One thing I did was do a full-screen fade in from black at the start of a level. Any visual glitches that occured during first-time image/audio processing were mostly hidden by the fade-in transition.
02/22/2006 (6:44 pm)
That behavior, while not looking the best, is actually probably what you'd prefer. I guess the the alternative is to frame-skip and just draw the scene at its most current point, but I think that'd look worse.It is a good idea to preload audio where possible and build pauses/loading screens/etc. into the flow where large sets of files are loaded to minimize the effect.
One thing I did was do a full-screen fade in from black at the start of a level. Any visual glitches that occured during first-time image/audio processing were mostly hidden by the fade-in transition.
#10
Using the "updateLevel" function above is completely inconsistant becase a millisecond is never the same length of time. This seems absurd to me. The speed of the game varies depending everything from the number of parallax backgrounds to the number of enemies on the screen. This cannot be right.
The real question here, I guess, is when should I update the physics? onUpdateScene doesn't work. Scheduling once a millisecond doesn't work. In fact, I think my weird "speed up" issue may be a result of doing this. Setting the target fps doesn't work.
I know someone has overcome this problem. What am I doing wrong? Melv? Anybody? Bueller? ;)
PS - @Melv - you mentioned this:
Any idea where that is?
03/01/2006 (4:33 pm)
I'm really not sure what to do next. I've got countless hours of development against something that I just cannot make work right.Using the "updateLevel" function above is completely inconsistant becase a millisecond is never the same length of time. This seems absurd to me. The speed of the game varies depending everything from the number of parallax backgrounds to the number of enemies on the screen. This cannot be right.
The real question here, I guess, is when should I update the physics? onUpdateScene doesn't work. Scheduling once a millisecond doesn't work. In fact, I think my weird "speed up" issue may be a result of doing this. Setting the target fps doesn't work.
I know someone has overcome this problem. What am I doing wrong? Melv? Anybody? Bueller? ;)
PS - @Melv - you mentioned this:
Quote:There was a post recently that showed how to make this call so that it occurs when the simulation is updated instead.
Any idea where that is?
#11
I'm not sure if 32 is a good number to use, but I seem to remember that 1 tick was classed as 32ms ? But I really have no idea if it's significant. *edit* actually 16 works much better for me.
Then I have the function:
generally seems to work, but I haven't tested on other machines yet, and I've also noticed the amount of objects that I have to go through in my For loop causes choppyness/delays..
03/01/2006 (5:39 pm)
I'm having similar confusion/problems, I didn't know about the onUpdateScene thing and physics, so what I've resorted to doing is creating a variable called $sceneTimer when the game starts, and then setting $scenetimer.setTimerOn(32);I'm not sure if 32 is a good number to use, but I seem to remember that 1 tick was classed as 32ms ? But I really have no idea if it's significant. *edit* actually 16 works much better for me.
Then I have the function:
function t2dSceneObject::onTimer(%this)
{
if ( %this = $scenetimer )
{
if ( $runTime.getCount() > 0 )
{
%runTimeCount = $runTime.getCount();
for ( %i=0; %i<%runTimeCount; %i++)
{
$runTime.getObject(%i).update();
}
}
if ( bulletData.getCount() > 0 )
{
%bulletCount = bulletData.getCount();
for ( %i=0; %i<bulletData.getCount(); %i++)
{
}
}
}
}generally seems to work, but I haven't tested on other machines yet, and I've also noticed the amount of objects that I have to go through in my For loop causes choppyness/delays..
#12
03/01/2006 (5:42 pm)
Also, the behavior with everything running faster periodically, well, what if we don't want this kind of behavior? It kind of makes certain types of games harder to play if the gameplay speeds up irratically, causing the player to collide with enemies and stuff.
#13
03/01/2006 (5:45 pm)
@ezra - Exactly! "Okay Mario. You just run a hundred miles an hour oh wait I mean 3 miles an hour oh wait you hit a turtle oh wait you are dead." Doesn't really fly. :)
#14
The only problem I have with this, is the speedup that happens, which I don't really understand why it happens, but it seems to happen coming right after a slowdown occurs, maybe just the time the physics system is saying, ok lets settle back down to normal, so it's re-adjusting, since it had just been running in time slices prior to that, to match the slowdown/whatever.. gah.. I don't know :D
The type of game I'm making requires the player to accurately avoid enemies and bullets (a shooter), so if the game runs slower than it's meant to, thats ok, just don't run faster than it's supposed to.. (which is occuring with setScenePhysicsFPSActive(true); and also $scenegraph.setScenePhysicsTargetFPS(60);)
03/01/2006 (6:06 pm)
There might be something I'm just not quite understanding though, I've been working on my game with setScenePhysicsFPSActive(false); and really the only problems which would come from slowdown is framerate choppyness, which so far has been OK with me, but now I'm assuming I should be running with setScenePhysicsFPSActive(true);, so that I can be confident that the physics will run correctly even on some high performance system.The only problem I have with this, is the speedup that happens, which I don't really understand why it happens, but it seems to happen coming right after a slowdown occurs, maybe just the time the physics system is saying, ok lets settle back down to normal, so it's re-adjusting, since it had just been running in time slices prior to that, to match the slowdown/whatever.. gah.. I don't know :D
The type of game I'm making requires the player to accurately avoid enemies and bullets (a shooter), so if the game runs slower than it's meant to, thats ok, just don't run faster than it's supposed to.. (which is occuring with setScenePhysicsFPSActive(true); and also $scenegraph.setScenePhysicsTargetFPS(60);)
#15
then with my physicsTargetFPS at 60 and my LimitFPS at 30, and iterations at 2, I was able to resolve the burst of speed that would sometimes occur when the framerate dips and then rises back to a large amount.. I'm not sure if this defeats the whole purpose of having setScenePhysicsFPSActive(true); though, but at least it seems to be working ok on my pc.. need to test it on others :D
03/01/2006 (7:58 pm)
I was reading this thread, http://www.garagegames.com/mg/forums/result.thread.php?qt=39997 and I decided to try setting $Pref::timeManagerProcessInterval = 16.666; which results in basically 60fps max.then with my physicsTargetFPS at 60 and my LimitFPS at 30, and iterations at 2, I was able to resolve the burst of speed that would sometimes occur when the framerate dips and then rises back to a large amount.. I'm not sure if this defeats the whole purpose of having setScenePhysicsFPSActive(true); though, but at least it seems to be working ok on my pc.. need to test it on others :D
#16
I found the framework for this code in another thread but I can't locate it now.
@Ezra, you're right about 32 milliseconds. That does seem to make everything smoother. Odd.
This still seems goofy, but it generally works. Here and there there's a smidgen of flicker, but nothing offensive. I can't help feeling this method is reinventing the wheel and there's something obvious I'm missing.
03/01/2006 (10:40 pm)
Okay, I've had some luck with this. I'm back to using onUpdateScene, but actually checking a ticker manually, like so:function t2dSceneGraph::onUpdateScene(%this)
{
if (t2dscene.getSceneTime() >= $nextSceneTick)
{
// do my time sensitive stuff right here
for (%i = 0; %i < EnemyGroup.getCount(); %i++)
{
updateEnemy(EnemyGroup.getObject(%i));
}
for (%i = 0; %i < VatorGroup.getCount(); %i++)
{
updateVator(VatorGroup.getObject(%i));
}
updatePlayer();
$camera.update();
$nextSceneTick = t2dscene.getSceneTime() + 0.032 ; // 32 msecs
}
}I found the framework for this code in another thread but I can't locate it now.
@Ezra, you're right about 32 milliseconds. That does seem to make everything smoother. Odd.
This still seems goofy, but it generally works. Here and there there's a smidgen of flicker, but nothing offensive. I can't help feeling this method is reinventing the wheel and there's something obvious I'm missing.
#17
To take your code for example:
I hope this helps
You can't do speed independent calculations without using time difference.
While fixing to a max of 30FPS might seem to solve the problem, it will reappear when the FPS drops below that, for whatever reason.
03/07/2006 (8:20 am)
The simplest thing would be using the hint melv gave above: Do stuff depending on elapsed time ...To take your code for example:
function t2dSceneGraph::onUpdateScene(%this)
{ // it is assume that you set up $lastUpdate = t2dscene.getSceneTime() before the simulation started
%tdiff = (t2dscene.getSceneTime() - $lastUpdate) / 1000.0;
// Now do all stuff depending on this tdiff value.
// As all the physical sizes should be defined in "value per second", you can simply do a *%tdiff in your calculation of the value change / applied.
// Note: All physical depending things base on %tdiff!
for (%i = 0; %i < EnemyGroup.getCount(); %i++)
{
updateEnemy(EnemyGroup.getObject(%i),%tdiff);
}
for (%i = 0; %i < VatorGroup.getCount(); %i++)
{
updateVator(VatorGroup.getObject(%i),%tdiff);
}
updatePlayer(%tdiff);
$camera.update(%tdiff);
$lastUpdate = t2dscene.getSceneTime() // Time the actual update finished
}
}I hope this helps
You can't do speed independent calculations without using time difference.
While fixing to a max of 30FPS might seem to solve the problem, it will reappear when the FPS drops below that, for whatever reason.
Torque Owner Jaybill
This is a fairly cripling problem that doesn't seem to have an obvious answer. It must happen to everyone who uses that platformer tutorial as the basis for a game. Everything I've read on the subject seems to say "close your eyes and let the framerate-independant physics engine solve your problem".
The truth is, the thing just runs slower at higher resolutions. This is to be expected, from a graphics point of view, but shouldn't the physics engine know where stuff is supposed to be and update accordingly?
I even tried replacing the "onUpdateScene" method with my own function that scheduled calls to itself every 1 millisecond. The results were identical. Apparently, time is dependant on framerate!
Help!