我该如何使用SDL2 iOS应用程序事件?

6

我目前正在使用SDL2库和C语言编写一个iPhone应用程序,大部分情况下都进展顺利。不幸的是,文档在某些方面似乎相当薄弱,特别是iOS专有函数。我刚开始使用SDL2,这使得事情非常困难。到目前为止,一切都很顺利,但我遇到了一个难题。SDL2定义了六种事件类型,专门用于移动应用程序。README-ios.txt文件描述了它们,并如下使用:

int HandleAppEvents(void *userdata, SDL_Event *event)
{
    switch (event->type)
    {
    case SDL_APP_TERMINATING:
        /* Terminate the app.
           Shut everything down before returning from this function.
        */
        return 0;
    case SDL_APP_LOWMEMORY:
        /* You will get this when your app is paused and iOS wants more memory.
           Release as much memory as possible.
        */
        return 0;
    case SDL_APP_WILLENTERBACKGROUND:
        /* Prepare your app to go into the background.  Stop loops, etc.
           This gets called when the user hits the home button, or gets a call.
        */
        return 0;
    case SDL_APP_DIDENTERBACKGROUND:
        /* This will get called if the user accepted whatever sent your app to the background.
           If the user got a phone call and canceled it, you'll instead get an    SDL_APP_DIDENTERFOREGROUND event and restart your loops.
           When you get this, you have 5 seconds to save all your state or the app will be terminated.
           Your app is NOT active at this point.
        */
        return 0;
    case SDL_APP_WILLENTERFOREGROUND:
       /* This call happens when your app is coming back to the foreground.
           Restore all your state here.
       */
        return 0;
    case SDL_APP_DIDENTERFOREGROUND:
        /* Restart your loops here.
           Your app is interactive and getting CPU again.
        */
        return 0;
    default:
        /* No special processing, add it to the event queue */
        return 1;
    }
}

int main(int argc, char *argv[])
{
    SDL_SetEventFilter(HandleAppEvents, NULL);

    //... run your main loop

    return 0;
}

我对这段代码有几个问题。

SDL_SetEventFilter() 函数是做什么的?我阅读了 SDL Wiki 页面,但似乎解释得不够清晰。

HandleAppEvents() 函数在实践中是如何工作的?例如,如果我的代码如下:

int main(int argc, char* argv[])
{
    //Initialize SDL, etc...
    SDL_SetEventFilter(HandleAppEvents, NULL);


    //I've got some SDL_Textures and windows and things...
    SDL_Window* my_window;
    SDL_Renderer* windowrend;
    SDL_Texture* tex1, tex2, tex3;

    //Primitive game loop
    while(game_is_running){
        handle_input();
        do_logic();
        update_screen();
    }

    destroy_all_my_data();
    SDL_Quit();
    return 0;
}

什么样的代码应该放在HandleAppEvents()或main()中,以便在收到SDL_APP_WILLENTERBACKGROUND等消息时销毁内存或停止游戏循环?
例如,如果应用程序收到SDL_APP_LOWMEMORY,则可以删除tex2。如何在HandleAppEvents()中删除tex2而不影响其他数据? userdata指针中有什么?
当我的应用程序进入后台时,我应该将纹理转换为表面,并将它们保存在../tmp/目录中作为bmp文件,还是当应用程序回到前台时它们仍然在内存中?
希望我的问题没有让您感到困惑。如果有一个地方可以找到关于SDL2的详尽文档,那就太好了。
谢谢您的查阅!
2个回答

7

SDL_SetEventFilter是一种“超前”于SDL事件队列的方法。你可以在它们被放入队列之前直接获取这些事件,而在iOS情况下,你必须立即对它们做出反应。

技术原因是,对于这些类型的消息,iOS使用一系列回调,SDL接收并包装它们,以使跨平台体验尽可能无缝,但事实仍然是,iOS期望你在从回调返回之前对其进行操作。

例如,如果我们只是将系统内存不足的消息放入队列中,而不是通过此机制将其直接传递给应用程序,那么你就只能等待该事件通过队列、轮询等方式到达,如果你什么都不做,iOS可以强制关闭你的应用程序,因为它的行为不符合预期。

当应用程序进入后台时,你不需要保存纹理。iOS会为你保存,如果它没有足够的内存来保存,它就会杀死你的应用程序(你永远不会失去GL ES/ES2上下文,这是某些Android设备可能会发生的情况)。

userdata指针将包含你作为第二个参数传递给SDL_SetEventFilter的数据,因此,如果你使用SDL_SetEventFilter(HandleAppEvents, NULL),userdata将为NULL。

在SDL_APP_WILLENTERBACKGROUND时,如果我没记错的话,你不需要做任何事情。我已经很久没有启动我的iOS应用程序了,但我认为SDL会自行处理其所有内部状态(包括阻止事件循环然后重新启动它)。你必须自己处理的事件是SDL_APP_LOWMEMORY和SDL_APP_TERMINATING,如何处理取决于应用程序本身(删除纹理、释放内存等,这超出了SDL的范畴)。


非常感谢您提供了一份有价值的答案。如果您有时间,我真的很想看到一些能够详细解释您意思的代码!+1 - BrainSteel
我认为在这种情况下不适用代码示例,因为您主要在问“哲学”问题,而代码有用的地方是在应用程序特定部分(SDL_APP_LOWMEMORY等)...但我没有可以提供的示例,在那里它可能涉及释放资源并跟踪它们以在需要时重新创建它们。但如果您想要答案的澄清,请随时提问! - gabomdq
好的,我明白你的意思。稍后我会更新问题并附上代码,希望通过你的反馈能更好地理解这个主题。 - BrainSteel

1

根据此线程的内容,你需要在SDL_APP_WILLENTERBACKGROUND停止游戏循环,并在SDL_APP_WILLENTERFOREGROUND上恢复它以避免崩溃。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接