Войти
iPhoneФорумПрограммирование

Свой Main Loop и Cocoa Touch

Страницы: 1 2 Следующая »
#0
22:50, 4 дек 2011

Здравствуйте. Проблема, с которой я столкнулся, не тривиальна совсем, но выход найти очень нужно.
У меня есть свой игровой движок, который имеет свой Main Loop - цикл, в котором все время "вертится" приложение. По дизайну, "разорвать" этот цикл нельзя - приложение живет, пока я в этом цикле, и умирает, когда я из него выхожу. Примитивно это можно представить так:

do
{
  опросить ввод;
  обработать логику;
  нарисовать;
}
while (!quit)

Эту структуру разрывать нельзя, я не могу вызвать внутренности отдельно, например, по таймеру или еще как-либо.
С виндой и MacOS такая структура прокатывает: винда не навязывает своего цикла, а в MacOS цикл можно "разорвать", воспользовавшись недокументированными возможностями  :shuffle:
Но в Cocoa Touch так не получается. В UIKit свой модальный цикл, и разрывать его она никому не дает, а два модальных цикла в одном потоке не уживаются. Я решил эту проблему путем создания нового потока - Cocoa крутит свой цикл в своем, а моя игра - в своем, и общение между ними происходит через performSelectorOnMainThread (сама Cocoa Touch однопоточна).
Все более-менеее работало, пока не потребовалось внедрить сторонний компонент, который, также как и моя игра, рисует в OpenGL. Они начали "бодаться" и в результате начались падения. Помучавшись, я понял, что лучше всего мне будет избавиться от двух потоков. Но как это сделать?
У меня две идеи, но в каждой есть вопросы:
1. Как-то разорвать модальный цикл Cocoa. Для этого мне нужно знать устройство их главной функции, главного цикла. Может, у кого-то есть документация, исходный код?
2. Реализовать цикл движка как сопрограмму, фибер, микропоток. Но в дурацкой IOS set_context-get_context-swap_context не работают! А если пытаться эмулировать фиберы на потоках - не получится ли одно и то же?
Нет ли других решений?

#1
23:06, 4 дек 2011

Избавиться от левого компонента не вариант?

#2
23:06, 4 дек 2011

Went
> Помучавшись, я понял, что лучше всего мне будет избавиться от двух потоков. Но как это сделать?

> По дизайну, "разорвать" этот цикл нельзя
рви по логике

#3
23:22, 4 дек 2011

KaronatoR
> Избавиться от левого компонента не вариант?
BFG обидится, если я избавлюсь от их рекламы :)

optimist32
> рви по логике
Не понял :) Под выражением "по дизайну" имеется в виду, что разорвать совсем нельзя, так уже сделано, переделывать очень трудно (движок использует модальные диалоги).

#4
0:08, 5 дек 2011

У меня для тебя плохие новости. Твой движок спроектирован коряво. И скорее все быстрее и лучше будет отрефакторить его сейчас, нежели латать подобные дыры.

#5
0:17, 5 дек 2011

Sergio
> Твой движок спроектирован коряво
No U!

#6
2:29, 5 дек 2011

Went
Наверно, ты хотел сказать
Изображение
:)

Но реально встраивание в ранлун UIApplication - это костыль из костылей. Что мешает сделать обновление всего того же по таймеру внутри UIApplicationDelegate?

#7
4:28, 5 дек 2011

Sergio
+1

#8
10:14, 5 дек 2011

А сделать отдельный контекст для BFGLib не получится? И пусть она им пользуется. Нам еще предстоит интегрировать ее. Вот интересно в чем именно сложность (я пока ее даже не видел )

#9
11:29, 5 дек 2011

Sergio
> Наверно, ты хотел сказать...
Нет, я хотел сказать
Изображение
:)

> Что мешает сделать обновление всего того же по таймеру внутри UIApplicationDelegate?
У меня в движке используются модальные диалоги. То есть код такого вида (псевдокод):

MessageDlg dlg("Are you sure?");
if (dlg.do_modal() == yes)
  do_something();

Как ты понимаешь, внутри вызова do_modal крутится МОЙ модальный цикл, который не отдаст управление вызвавшему контексту до тех пор, пока диалог не завершится с каким-то результатом.
Поэтому, в момент отработки этого диалога весь UIKit подвиснет, перестанет отдавать мне клавиатуру, и программа уйдет в бесконечное ожидание.

Стас
> А сделать отдельный контекст для BFGLib не получится?
А она не спрашивает, какой контекст использовать - просто коннектится к корневому вью контроллеру. Теоретически, у нее и должен быть свой контекст, но почему-то коллизии происходят. Везде пишут, что UIKit абсолютно однопоточен, поэтому удивляться не приходится.

#10
13:02, 5 дек 2011

Тогда еще хуже. Получается, что у тебя будет висеть не только UIKit, но и на любой другой платформе тоже. Если в этом потоке, например, будут крутиться сокеты - им тоже жопа настанет, и так далее.
Выходов несколько:
1) переделать движок так, чтобы в нем не было элементов, которые требую модальности;
2) переделать движок так, чтобы вся модальность была как-бы внешней по отношению к процессу (проще говоря обновление по таймеру)
3) сделать диалоговое окно платформеннозависимым и использовать модальный UIAlertView.

#11
13:12, 5 дек 2011

Sergio
> Получается, что у тебя будет висеть не только UIKit, но и на любой другой
> платформе тоже
На винде и маке все ОК :) С андроидом прозреваю подобную проблему, да.

> Если в этом потоке, например, будут крутиться сокеты - им тоже жопа настанет, и так далее.
Решал без проблем, если правильно тебя понял.

> 1) переделать движок так, чтобы в нем не было элементов, которые требую
> модальности;
Да, это - крайняя мера.

Sergio
> 2) переделать движок так, чтобы вся модальность была как-бы внешней по
> отношению к процессу (проще говоря обновление по таймеру)
Это не понял. Вынести в отдельный поток?

Sergio
> 3) сделать диалоговое окно платформеннозависимым и использовать модальный
> UIAlertView.
Там не только в диалогах проблема. Модальные циклы внутри функций используются повсеместно. Это удобно :)

#12
13:20, 5 дек 2011

Went
Как видишь, за такое удобство приходится расплачиваться.
Смысл такой, что вместо
while (modal) do ...

Ты делаешь примерно так:

void Update() {
...
if (modalEndCondition) {
modal = false;
returnControl();
}
}

И вызываешь это обновление, скажем так, по таймеру.

#13
13:29, 5 дек 2011

Sergio
Ну, это, фактически, и есть "отказ от модальности" с эмуляцией оной на апдейтах или событиях.

Вести с полей: если вызывать рендер из главного потока, вроде как, коллизий не наблюдается.

#14
13:36, 5 дек 2011

Как бы  переделать уже готовую игру это немного жесткая мера. И честно говоря не вижу особенного удобства в использовании подобного решения.
Возможность блокировки выполнения основного кода?  Ну это можно решить немного другими способами. Например у меня это решается за счет передачи управления только модальным объектам (если они есть ):

bool cGameObject::ProcessInput( bool bModal )
{
    if( bModal )
    {
        PreProcessInput();
        if( DoProcessInput() )
       {
           return true;
       }
    }
    else
    {
        PreProcessInput();
        bModal = cGameScene::instance()->GetModal() == this;
        if( bModal )
        {
             if( DoProcessInput() )
            {
                return true;
            }
        }
    }

А вызов окна сообщения делается примерно таким образом:

  wstring title = cTextManager::instance()->get_text( "exit_title" );
  wstring message = cTextManager::instance()->get_text( "exit_message" );
  cGameMessageBox( title, message, MakeCallback( this, &cGameInit::OnExitGame ), 0 );  

Но пока я не видел собственно проблемной библиотеки.. Сказать наверняка что эти советы помогут не могу.

Страницы: 1 2 Следующая »
iPhoneФорумПрограммирование

Тема в архиве.