我正在计划一个使用SDL的小型Vala游戏项目,我想知道如何将SDL正确地集成到GLib主循环中。我最后一次使用Vala和SDL做了一些事情,我使用了标准的SDL事件循环,但老实说,它是一堆废话,它打破了整个不错的Vala或GLib信号系统。
我找到了an integration for Cogl,我正在寻找与SDL相同的东西。
答案 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.EventMask
和SDL.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事件。您可以使用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。