对于我自己的 iOS 项目,我使用经典方法(创建一个窗口 .nib,创建一个继承类EAGLView
,添加EAGLView
到放置在其自己的 .nib 中的视图控制器中的视图)。
在工作中,我采用了一种受 SDL 启发的稍微不同的方法,您可以在我们的开源库APRIL中查看它。APRIL 的主要目标是支持尽可能多的平台,同时保持简单性(仅限窗口和输入管理)并明确许可问题并免费使用。我们的开发人员希望在一个平台(Windows、Mac 或 Linux,根据口味和需求)编写应用程序,然后将代码交给我以适应其他平台。
在我们在 APRIL 中使用的方法中,您不创建任何 .nib,并且在调用 时UIApplicationMain
,您将委托类指定为其第四个参数。游戏的主要代码对于每个平台都保持完全相同,只有特定于平台的内容被#ifdef
写入代码中,或者抽象到帮助程序库中。
在应用程序委托中,您创建视图控制器和窗口:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// create a window.
// early creation so Default.png can be displayed while we're waiting for
// game initialization
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// viewcontroller will automatically add imageview
viewController = [[AprilViewController alloc] initWithWindow:window];
[viewController loadView];
// set window color
[window setBackgroundColor:[UIColor blackColor]];
// display the window
[window makeKeyAndVisible];
// thanks to Kyle Poole for this trick
// also used in latest SDL
// quote:
// KP: using a selector gets around the "failed to launch application in time" if the startup code takes too long
// This is easy to see if running with Valgrind
[self performSelector:@selector(runMain:) withObject:nil afterDelay:0.2f];
}
请注意我们如何将启动延迟 0.2?这就是我在上面提到图像视图的原因。在这 0.2 秒内,我们会在 Default.png 之后立即显示空白屏幕,并且在将控制权转移到 runMain: 之前引入了额外的延迟,这会将控制权释放给主应用程序:
- (void)runMain:(id)sender
{
// thanks to Kyle Poole for this trick
char *argv[] = {"april_ios"};
int status = april_RealMain (1, argv); //gArgc, gArgv);
#pragma unused(status)
}
因此,现在控件永远不会转移回 UIApplication 的实际主循环。然后创建自己的主循环。
void iOSWindow::enterMainLoop()
{
while (mRunning)
{
// parse UIKit events
doEvents();
handleDisplayAndUpdate();
}
}
void iOSWindow::doEvents()
{
SInt32 result;
do {
result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, TRUE);
} while(result == kCFRunLoopRunHandledSource);
}
(附带说明一下,当然,使用视图控制器来简化 UI 的旋转以匹配设备方向。)
CADisplayLink
如果操作系统支持,这两种方法都可以使用。尽管我的私人项目主要基于加速度计,但我没有注意到这两种方法有任何问题。我怀疑 APRIL 方法也可能使一些问题消失。