我正在尝试将游戏库移植到iPhone。与SDL不同,此库不能完全控制您的main()函数,而是通过您自己的代码中的快速返回函数与之通信的。因此,例如,明显的伪代码:
int main() {
library_init();
// game init code here
while(we_have_not_quit_the_game) {
library_message_loop();
library_init_render();
// render stuff
library_end_render();
// update game state
}
library_shutdown();
}
iPhone使这一点变得困难,因为它要求您调用一个永不返回的UIApplicationMain函数。在library_init();之后,根本无法回到用户代码。
我不认为这是必要的-据说可以使用NSRunLoop来处理事件。但是,我不知道UIApplicationMain是否做其他重要的事情。 (请注意,我没有使用.nib文件的计划,这是我发现UIApplicationMain可以做的唯一另一件事。)
我有三个可以想到的真实想法,但是它们都是主要的实现工作,因此我想在一天尝试失败的想法之前弄清楚是否有人对此有经验。
有什么建议吗?
最佳答案
看来我在这里回答自己的问题!在我能够在真实的硬件上对其进行测试并将其放入应用商店之前,我不会接受我的回答。也就是说,我将在此处保留我的最新信息,包括哪些选项不起作用。
想法#1 :事实证明,每个NSRunLoop都是特定于线程的。如果我在单独的线程中创建UIApplicationMain,则不会收到任何消息。作为副作用,这使得无法确定何时完成初始化,因此,如果有任何非线程安全的功能,它将无法正常工作。我也许可以跨线程向它发送一条消息,以弄清何时完成初始化,但是现在我称之为死胡同。
想法2 :UIApplicationMain做很多细微的事情。我不确定它的限制,但是如果不涉及UIApplicationMain,我将无法使任何工作。想法2是正确的。
想法3::接收操作系统信号很重要-您需要知道是否有电话覆盖,或者是否要退出。最重要的是,为了正确启动应用程序,一些设置消息似乎至关重要。我无法找到任何方法来保持消息的发送而无需进入UIApplicationMain。我想到的唯一选项是NSRunLoop和CFRunLoop。两者均无济于事-消息没有按我想要的那样传入。我可能没有使用这些权利,但是在任何情况下,想法3都是可行的。
全新的疯狂创意#4 :可以在C/C++中使用setjmp/longjmp来伪造协程。诀窍是首先将堆栈指针设置为不会破坏任何重要内容的值,然后启动第二个例程,然后来回跳转,假装您有两个堆栈。如果您的“第二协程”决定从其主函数返回,则事情会变得有些困惑,但是幸运的是,UIApplicationMain从不返回,因此这不是问题。
我不知道是否有一种方法可以在真正的硬件上显式设置堆栈指针,例如,设置为我动态分配的数据块。幸运的是,没关系。 iPhone默认情况下具有1MB的堆栈,足够容纳几个协程。
我当前正在做的是使用alloca()将堆栈指针向前推768 KB,然后生成UIApplicationMain,然后使用setjmp/longjmp在“UI例程”和“主例程”之间来回弹跳。到目前为止,这是可行的。
注意事项:
我会保持最新状态,并在我确认它可以正常工作后正式接受它。
后期更新:我因其他各种事情而分心。从那时起,我进行了一些更改,使我对Apple开发的兴趣大大降低。我目前的方法没有任何迹象表明它不起作用,但是我真的没有动力继续充实它。对不起!如果我改变主意,将进一步进行更新,但是Outlook不太好。