Ответ 1
Для моих собственных проектов iOS я использую классический подход (создайте окно .nib, создайте класс, наследующий EAGLView
, добавьте EAGLView
в представление в контроллере представления, который помещен в свой собственный .nib).
На работе я использовал несколько иной подход, основанный на SDL, который вы можете проверить в нашей раскрываемой библиотеке, APRIL. Основная цель APRIL - поддержка как можно большего числа платформ, сохраняя простоту (только управление окнами и вводами), а также четкое описание вопросов лицензирования и возможность использования. Наши разработчики хотят писать приложения на одной платформе (Windows, Mac или Linux, в соответствии с вкусами и желаниями), а затем мне передается код для адаптации к другим платформам.
В подходе, который мы используем в APRIL, вы не создаете никаких .nib, а при вызове UIApplicationMain
вы указываете класс делегата как свой четвертый аргумент. Основной код игры остается абсолютно одинаковым для каждой платформы, и только код для конкретной платформы #ifdef
'd в код или абстрагируется в вспомогательной библиотеке.
В делегате приложения вы создаете контроллер представления и окно:
- (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);
}
(На стороне примечание, контроллер просмотра используется, конечно, для упрощения вращения пользовательского интерфейса для соответствия ориентации устройства.)
Оба этих подхода используют CADisplayLink
, если они поддерживаются ОС. Я не заметил никаких проблем с любым из методов, хотя мои частные проекты в основном основаны на акселерометре. Я подозреваю, что подход APRIL может также устранить некоторые проблемы.