Quick and dirty multitasking (background suspend)
by Craig Fortune · in iTorque 2D · 07/30/2010 (12:02 am) · 16 replies
Is it just me, or is it a little weird that iTGB doesn't have a default case for background suspend? Or is there one and I'm just overlooking it?
Anyway, the following changes will make your game loop stop when a user presses the home button or whenever else the device decides the app needs to resign the focus it has. It will allow it to run again when you start the app again. Quick, dirty, but does the job.
Make these changes in IPhoneMain.mm starting around line 77
You'll need to handle time stuff too, to make sure any timed things don't go out of whack.
Anyway, the following changes will make your game loop stop when a user presses the home button or whenever else the device decides the app needs to resign the focus it has. It will allow it to run again when you start the app again. Quick, dirty, but does the job.
Make these changes in IPhoneMain.mm starting around line 77
bool bDoNotRun = false;
S32 gLastStart = 0;
void _iPhoneGameInnerLoop()
{
if(bDoNotRun)
{
return;
}
else if(Game->isRunning())
{
S32 start = Platform::getRealMilliseconds();
Game->mainLoop();
S32 time = sgTimeManagerProcessInterval - (start - gLastStart);
gLastStart = start;
if(!CAdisplayLinkSupported)
{
iPhoneRunEventLoopTimer(time);
}
}
else
{
Game->mainShutdown();
//Luma: Need to actually exit the application now
exit(0);
}
}
void _iPhoneGameResignActive(){
Con::executef( 1, "oniPhoneResignActive" );
bDoNotRun = true;
}
void _iPhoneGameBecomeActive(){
bDoNotRun = false;
Con::executef( 1, "oniPhoneBecomeActive" );
}You'll need to handle time stuff too, to make sure any timed things don't go out of whack.
About the author
#2
realtime means: on each update run, add the simulation step timelength to an accumulator, don't do time difference measures through currentTime - newTime, thats granted to fail misserably as already a phone call would mess your whole handling totally
07/30/2010 (2:02 pm)
realtime when done right should be no problem too :)realtime means: on each update run, add the simulation step timelength to an accumulator, don't do time difference measures through currentTime - newTime, thats granted to fail misserably as already a phone call would mess your whole handling totally
#3
07/30/2010 (2:04 pm)
REAL time, not realtime.
#4
sgx error (background gpu access not permitted):
Program received signal: “SIGABRT”.
08/17/2010 (1:23 am)
Thanks for this post. Actually, it looks like you HAVE to use this fix, otherwise the application crashes on exit when you press the iPhone Home button:sgx error (background gpu access not permitted):
Program received signal: “SIGABRT”.
#5
08/17/2010 (7:31 am)
Hmm... I haven't tried to activate suspend. This would require the addition of a quit button - something the boss lady hasn't planned for in the design of the game. I am glad to see that it exits on home button if you *haven't* implemented suspend (even if it is a crash, technically).
#6
Yes, that's right. What is actually happening there is that you aren't allowed to do any graphics calls when you are in the background. Prior to applying this change the app will try to continue going in the background (including rendering!) and thus the device decides to kill the process off.
@Sarah
Addition of a quit button? Hmm?
All iOS apps will exit upon the home button being pressed. They don't have a choice, the OS just gives you a warning that it is going to happen.
08/17/2010 (12:48 pm)
@RichardYes, that's right. What is actually happening there is that you aren't allowed to do any graphics calls when you are in the background. Prior to applying this change the app will try to continue going in the background (including rendering!) and thus the device decides to kill the process off.
@Sarah
Addition of a quit button? Hmm?
All iOS apps will exit upon the home button being pressed. They don't have a choice, the OS just gives you a warning that it is going to happen.
#7
08/18/2010 (2:12 am)
I modified it a little to actually stop the game loop from running and so that it will work on devices that don't support CADisplayLink. Replace _iPhoneRunTorqueMain, _iPhoneGameResignActive, _iPhoneGameBecomeActive in iPhoneMain.mm with these versions. Leave _iPhoneGameInnerLoop as it was in the download.int _iPhoneRunTorqueMain( id appID, UIView *Window, UIApplication *app )
{
platState.appID = appID;
platState.firstThreadId = ThreadManager::getCurrentThreadId();
platState.Window = Window;
platState.application = app;
//Hidden by default.
platState.application.statusBarHidden = YES;
#if !defined(TORQUE_MULTITHREAD)
printf("performing mainInit()n");
platState.lastTimeTick = Platform::getRealMilliseconds();
if(!Game->mainInit(platState.argc, platState.argv))
{
return 0;
}
//Luma: CADisplayLink main loop support
//Currently needs to move to app delegate or platstate.
NSString *reqSysVer = @"3.1";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending)
CAdisplayLinkSupported = YES;
//Need a true or it will think its crashed, and fail.
return true;
#else
#endif
}
void _iPhoneGameResignActive(){
Con::executef( 1, "oniPhoneResignActive" );
// invalidate the timer so the game loop will stop
if (CAdisplayLinkSupported)
{
[displayLink invalidate];
displayLink = nil;
}
else
{
[platState.mainLoopTimer invalidate];
platState.mainLoopTimer = nil;
}
}
void _iPhoneGameBecomeActive(){
Con::executef( 1, "oniPhoneBecomeActive" );
// start the game loop running again
if (CAdisplayLinkSupported)
{
//We can use the CADisplayLink to update the game now.
//Luma: The magic number 1 below is because of what the docs say.
/*
The default value is 1, which results in your application being notified at the refresh rate of the display.
If the value is set to a value larger than 1, the display link notifies your application at a fraction of the
native refresh rate. For example, setting the interval to 2 causes the display link to fire every other frame,
providing half the frame rate.
Setting this value to less than 1 results in undefined behavior and is a programmer error.
*/
NSInteger updateDelay = 1;
displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:platState.appID selector:@selector(runMainLoop)];
[displayLink setFrameInterval:updateDelay];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
else
{
iPhoneRunEventLoopTimer(0);
}
}
#8
08/18/2010 (12:15 pm)
/like
#9
09/08/2010 (2:08 pm)
Thank you, thank you, thank you. Now I can check this off my list.
#10
10/05/2010 (11:02 pm)
Wow! This was driving me nuts! Thanks! Whoever is in charge, make sure this gets added to the source and for god's sake give this man a cookie!
#11
11/11/2010 (9:50 pm)
I too proffer a cookie to all parties involved. Hell, you can take a cooke -each-.
#12
12/06/2010 (6:00 pm)
Thanks Robert and Craig! This totally rocks!
#13
04/05/2011 (3:06 pm)
Anyone used this with 1.4.1 yet? I love this feature!
#14
04/06/2011 (9:00 pm)
I added this to my 1.4.1 source and it seems to work fine. But I don't know if this screws up anything else. Has anyone else used this? Is it okay with 1.4.1?
#15
Would like to see this in the next official release.
04/11/2011 (9:21 am)
1.4.1 was mostly a bugfix release, I can't see it causing any issues.Would like to see this in the next official release.
#16
08/26/2011 (10:34 pm)
I used both Cralg Fortune, and Robert Hughes solutions together in 1.4.1. It works, but something got screwed up with my touch screen input. Just updating, and I have not looked into it yet.
Associate Craig Fortune
Things like schedules, which are managed via the simulation, *should* work just fine. When the app goes into suspend they will simply be paused.