【问题标题】:Integrate SDL into GLib mainloop将 SDL 集成到 GLib 主循环中
【发布时间】:2016-07-10 16:05:04
【问题描述】:

我正在计划一个使用 SDL 的小型 Vala 游戏项目,我想知道如何将 SDL 正确集成到 GLib 主循环中。上次我使用 Vala 和 SDL 做某事时,我使用了标准的 SDL 事件循环,但老实说,这是一堆废话,它破坏了整个漂亮的 Vala 或者更确切地说是 GLib 信号系统。

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

【问题讨论】:

  • 不清楚你想做什么。如果您只想绘图,则向窗口添加重绘回调就足够了(并在发生需要更改显示图像的事情时触发重绘)。对于更常规的事情,有计时器和空闲功能。

标签: sdl glib vala


【解决方案1】:

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 dispatch 唤醒协程:

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;
}

【讨论】:

    【解决方案2】:

    遗憾的是,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。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-21
      • 1970-01-01
      • 2011-10-07
      • 1970-01-01
      • 2011-12-06
      相关资源
      最近更新 更多