{"id":806,"date":"2010-11-30T20:14:56","date_gmt":"2010-12-01T02:14:56","guid":{"rendered":"http:\/\/www.philhassey.com\/blog\/?p=806"},"modified":"2010-11-30T20:14:56","modified_gmt":"2010-12-01T02:14:56","slug":"adding-retina-multitasking-support-to-my-ios-apps","status":"publish","type":"post","link":"https:\/\/www.philhassey.com\/blog\/2010\/11\/30\/adding-retina-multitasking-support-to-my-ios-apps\/","title":{"rendered":"Adding Retina \/ Multitasking support to my iOS apps"},"content":{"rendered":"<p>Today I felt it was about time I got around to updating my Galcon apps with proper 4.x support now that everyone has it.<\/p>\n<p>Adding retina is pretty easy.  In EAGLView.m I had to add this snippet into initWithCoder:<\/p>\n<pre>\r\n\tfloat scale = 1;\r\n                \r\n        if([[UIScreen mainScreen] respondsToSelector:\r\n            NSSelectorFromString(@\"scale\")])\r\n            {\r\n             if([self respondsToSelector:\r\n                  NSSelectorFromString(@\"contentScaleFactor\")])\r\n                  {\r\n                     scale = [[UIScreen mainScreen] scale];\r\n                      self.contentScaleFactor = scale;\r\n                 }\r\n           }\r\n<\/pre>\n<p>Then in my code anywhere where the scale matters, I use that information to sort things out.  I found that adding retina Icons, startup graphics, and other in-game graphics was as easy as adding an extra file: Icon.png becomes Icon@2x.png, my_game_stuff.png becomes my_game_stuff@2x.png, etc.  It was pretty simple.  Fonts were a bit more complex because I have different font data for each sized font, so I use the scale information I discovered earlier to ensure that I use entirely different font images, instead of using the @2x trick.  The one goofy bit was importing to subversion.  It doesn&#8217;t work, unless you put a trailing @ at the end of the filename, since subversion treats @ as the version identifier.<\/p>\n<pre>\r\nDoesn't work:\r\nsvn add Icon@2x.png\r\n\r\nWorks:\r\nsvn add Icon@2x.png@\r\n<\/pre>\n<p>Multitasking was even easier.  In my AppDelegate.m I added these methods:<\/p>\n<pre>\r\n- (void)applicationDidEnterBackground:(UIApplication *)application\r\n{\r\n    game->save();\r\n\r\n    Event e; e.type = EVT_SUSPEND;\r\n    game->event(&e);\r\n    [glView stopAnimation];\r\n    \r\n}\r\n\r\n- (void)applicationWillEnterForeground:(UIApplication *)application\r\n{\r\n    Event e; e.type = EVT_RESUME;\r\n    game->event(&e);\r\n    [glView startAnimation];\r\n}\r\n<\/pre>\n<p>The first is called when the app is suspended, the second is called when the app resumes.  The iOS handles saving \/ restoring all the texture data, so really I didn&#8217;t have to do anything.  The only catch was I had to add in the glView stop\/start calls to ensure that no GL calls were made while the app was suspending.  The app will crash if any GL calls are made while in the background.<\/p>\n<p>I do not do any background work to keep the network alive.  This seems sensible because it makes it so the game will timeout after 30 seconds but you&#8217;ll still be connected if you get back sooner than that.  Anything fancier could keep a player on the network indefinitely even if they are really gone.  This gives the user at least a momentary opportunity to duck away and check something then resume playing.<\/p>\n<p>-Phil<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today I felt it was about time I got around to updating my Galcon apps with proper 4.x support now that everyone has it. Adding retina is pretty easy. In EAGLView.m I had to add this snippet into initWithCoder: float scale = 1; if([[UIScreen mainScreen] respondsToSelector: NSSelectorFromString(@&#8221;scale&#8221;)]) { if([self respondsToSelector: NSSelectorFromString(@&#8221;contentScaleFactor&#8221;)]) { scale = [[UIScreen [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-806","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.philhassey.com\/blog\/wp-json\/wp\/v2\/posts\/806","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.philhassey.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.philhassey.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.philhassey.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.philhassey.com\/blog\/wp-json\/wp\/v2\/comments?post=806"}],"version-history":[{"count":4,"href":"https:\/\/www.philhassey.com\/blog\/wp-json\/wp\/v2\/posts\/806\/revisions"}],"predecessor-version":[{"id":810,"href":"https:\/\/www.philhassey.com\/blog\/wp-json\/wp\/v2\/posts\/806\/revisions\/810"}],"wp:attachment":[{"href":"https:\/\/www.philhassey.com\/blog\/wp-json\/wp\/v2\/media?parent=806"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.philhassey.com\/blog\/wp-json\/wp\/v2\/categories?post=806"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.philhassey.com\/blog\/wp-json\/wp\/v2\/tags?post=806"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}