Подтвердить что ты не робот

Игры iOS и управление Run-Loop

Во-первых, мой вопрос: как вы справляетесь с Run-Loop iOS?

Далее моя причина: я исследовал это с помощью множества прототипов (v. разработка на ранней стадии) и обнаружил ряд недоумений.

  • Во-первых, проблемы ввода и цикл запуска заставляют меня попробовать следующее:
    • При использовании самой рекомендуемой системы (CADisplayLink) я заметил, что некоторые сенсорные входы отбрасываются, когда загрузка процессора вызывает пересылку буфера (presentRenderBuffer), чтобы ждать фрейма. Это происходит только на устройстве, а не в симуляторе (раздражающе - это, похоже, связано с ожиданием блокировки vsync на основном потоке и тем, как процесс запуска приложения работает и доставляет сообщения)
    • При использовании следующей наиболее рекомендуемой системы (NSTimer) я заметил, что некоторые сенсорные входы отбрасываются, когда загрузка процессора достигает определенной точки в симуляторе, но не в устройстве (также досадно). NSTimer также приводит к значительно меньшей точности, когда мои обновления срабатывают
    • при использовании наименее рекомендуемой системы (запуск цикла запуска в нем собственный поток, управляемый внутренне с помощью таймера высокой точности, построенного из mach_absolute_time, все мои проблемы с сенсорным входом исчезают, однако мой код ASSERT теперь ловушки в неправильном потоке и только если я сплю, следуя программному прерыванию. (Мой код подтверждения похож на http://iphone.m20.nl/wp/?p=1) Мне очень нравится, когда моя ловушка assert code сразу на линии что вызвало проблему, поэтому это решение для меня не работает: сложнее отлаживать.
  • Во-вторых, потерянное время:
    • при исследовании системы я обнаружил, что независимо от частоты кадров (странно, но я полагаю, что статистически это все еще имеет смысл w/vsync), я жду примерно 22% времени на vsync. Я подтвердил это, перемещаясь по glFlush/glFinish и играя с тем, как часто я выполняю вызовы presentRenderBuffer. Это ключевое время, которое я хотел бы обрабатывать AI и т.д., А не просто останавливаться на блокирующем вызове gl. Единственный способ, которым я могу думать обо всем этом, будет включать в себя перенос рендеринга в его собственный поток, но я не уверен, что это потребовало начать повторное архивирование для многопоточности на однопроцессорном устройстве.

Так кто-нибудь нашел волшебную пулю вокруг этих проблем? Есть ли у кого-нибудь кибер-зонная архитектура, которая подбрасывает эту платформу? На данный момент похоже, что я должен выбрать меньшее из зла.

4b9b3361

Ответ 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 может также устранить некоторые проблемы.