将SDL集成到GLib主循环中

时间:2016-07-10 16:05:05

标签: sdl glib vala

我正在计划一个使用SDL的小型Vala游戏项目,我想知道如何将SDL正确地集成到GLib主循环中。我最后一次使用Vala和SDL做了一些事情,我使用了标准的SDL事件循环,但老实说,它是一堆废话,它打破了整个不错的Vala或GLib信号系统。

我找到了an integration for Cogl,我正在寻找与SDL相同的东西。

2 个答案:

答案 0 :(得分:3)

GLib源由三个回调组成:

  • 在轮询之前检查源是否准备好(并避免poll呼叫)
  • 在轮询后检查来源是否仍然准备就绪
  • 一个派遣附加回调

您可以非常简单地检查和调度事件。

public delegate bool SDLSourceFunc (SDL.Event event);

public class SDLSource : Source 
{
    public SDL.Event event;

    public bool prepare (out uint timeout) 
    {
        timeout = 0;
        return true;
    }

    public bool check ()
    {
        return SDL.Event.poll (out event) > 0;
    }

    public bool dispatch (SourceFunc callback) 
    {
        return ((SDLSourceFunc) callback) (event);
    }

    public void add_callback (SDLSourceFunc callback)
    {
        base.add_callback ((SourceFunc) callback);
    }
}

然后,您将使用Source.CONTINUE循环:

var source = new SDLSource ();

source.add_callback ((event) => {
    // handle event here
    return Source.CONTINUE;
});

source.attach (MainContext.@default ());

这是非常基本的:您的来源可以使用SDL.EventMaskSDL.peep过滤特定事件。为单个源分派多个事件并附加相关文件描述符也更有效。

如果您使用某些异步代码,则可以直接从Source调度唤醒协程:

public async void next_event_async () 
{
    var source = new SDLSource ();
    source.attach (MainContext.@default ());
    source.add_callback (handle_event_async.callback);
    yield;
    return source.event;
}

答案 1 :(得分:1)

可悲的是,SDL非常困难。理想情况下,SDL API会提供一个文件描述符来监听,只要有事件可用就会发出信号,这样你就可以将它添加到glib主循环中,但它没有这个。

虽然它不太理想,但我认为最简单,最便携的方法就是安装定时器来定期检查SDL事件。您可以使用g_timeout_add执行此操作以定期唤醒主循环,然后在回调中调用SDL_PollEvent。

这类似于answer given by arteymix,除非要注意那里给出的方法会有效地导致忙等待(如果没有可用的事件,prepare函数返回零超时),所以最终总是使用100 %CPU。

Clutter曾经有一个SDL backend,你仍然可以在Git历史中看到它。它基本上采用这种方法定期唤醒主循环,除了它创建自定义源而不是使用g_timeout_add。

考虑到您正在编写游戏,如果您希望不断重绘并让该过程在SDL_GL_SwapWindow中定期阻塞,那么仅使用g_idle_add安装空闲处理程序更有意义,然后执行所有操作您的SDL内容在回调中。您可以检查空闲回调开始时的事件,然后在结束时调用SDL_GL_SwapWindow,阻止等待重绘完成,这意味着它不会占用100%的CPU。