【问题标题】:How to create a game loop with xlib如何使用 xlib 创建游戏循环
【发布时间】:2015-09-20 14:11:45
【问题描述】:

我正在尝试为 xlib 窗口创建游戏循环,但我无法正确绘制窗口。现在我正在使用 XCreateSimpleWindow(...) 创建一个窗口,并使用 for 循环一次绘制所有像素。 (这些像素的颜色是从一个大整数数组中读取的,现在我将所有像素设置为蓝色。)现在实际的游戏循环如下:

void loop() {
    while (true) {
        // Clear the window (the background color is set to white)
        XClearWindow(dsp, win);

        // Loop through all pixels of the 800*600 window
        for (int j = 0; j < 600; j++) {
            for (int i = 0; i < 800; i++) {
                // Read the color from the pixels array (always blue for now)
                long int color = pixels[i + 800*j];
                // Set the foreground color for drawing
                XSetForeground(dsp, gc, color);
                // Draw the pixel
                XDrawPoint(dsp, win, gc, i, j);
            }
        }

        // Flush the output buffer
        XFlush();
    }
}

变量 dsp、win、pixels、gc 是全局定义的。

现在当我编译和执行二进制文件时,y坐标低的行大多是蓝色的,而y坐标高的行大多是白色的。在这两者之间很容易看出一次绘制所有像素需要太多时间。我希望这种效果是因为首先绘制了顶行(低 y),这意味着这些像素的 XClearWindow() 和 XDrawPoint() 之间存在短暂的延迟。 (我还测试了 fps,运行一次 while(true) 循环大约需要 7 毫秒。)

我做了一些研究,并了解了双缓冲如何解决这个问题。我确实遵循了关于使用 xlib (Xdbe) 进行双缓冲的指南,但它似乎并没有解决问题。有没有比循环遍历所有像素更快的使用 xlib 绘图的方法?双缓冲不应该解决这个问题,还是我执行不正确?

【问题讨论】:

    标签: c++ linux x11 xlib


    【解决方案1】:

    您看不到任何东西的原因是您忽略了 X 事件循环。您所做的只是向 X 服务器发送数据,但 X 服务器无法返回通信。

    您必须设置一个循环,从队列中读取 XEvents 并分派 c.q。处理。比如:

    XEvent event;
    while (XPending (m_display))
    {
      XNextEvent (m_display, &event);
      if (XFilterEvent (&event, None))
      {
        continue;
      }
      switch (event.type)
      {
         case KeyPress:
           ..
         case ButtonPress:
           ..
         case Expose:
           ..
         case MapNotify:
           ..
         // etc
      }
    }
    

    不过,这可以与您的无限循环结合使用。

    但是,是的,逐像素绘制非常慢。我什至不想计算协议开销......:P

    【讨论】:

      【解决方案2】:

      90 年代初直接与 Xlib 通信(阅读:在过去的 20 年里,除非他是框架设计师,否则没有人这样做过!)。

      你是对的,循环通过像素在屏幕上更新它们是难以置信慢。这就是为什么几乎所有现代 GUI 框架都使用自己的 Xbuffers,它们只是在这些缓冲区上绘制并指示 X 进行渲染。

      作为对您的方法的评论: 在原始 X 上进行游戏开发毫无意义,因为有更多可移植性、性能更好、更易于使用、小型且经过良好测试的库。以 SDL 为例。

      2021 年 3 月更新:正如 Pablo Ariel 在下面指出的那样,现在可能需要指出的是,花时间学习 X11 并不是明智的投资:X 正在消失;这花了几十年的时间,但最大的 Linux 发行版(在 Debian 10 这样做之后,Ubuntu 21.04 也这样做了,因此像 Mint 这样的所有衍生产品都默认使用 Wayland;Fedora 34 也是如此)默认使用 Wayland;在这些上仍然可以使用 X11,但是使用旧的东西是一个额外的步骤......

      请注意,这并不意味着如果您想学习如何制作游戏,就应该学习 Wayland。或原始的OpenGL。或伏尔甘。图形/游戏引擎是你的朋友,因为你 a) 不想自己处理所有低级的东西,抽象出同一事物的不同版本之间的细微差异,并且 b) 你没有变得更快比写得很好的引擎,编写游戏引擎的人在这方面会比你更好。专注于相关部分,而不是处理最底层的库!

      【讨论】:

      • 感谢您的回复。我决定不使用 OpenGL 等库,因为我想了解一下这些库背后的数学知识。我的意思是我打算手动对旋转矩阵、投影等进行编程,而不仅仅是调用 OpenGL 函数。你的意思是我不应该因为 fps 的原因而这样做,还是有没有办法在没有这些库的情况下完成这项工作?
      • 您可以使用任何适当的 GUI 库在屏幕上绘制线条和颜色像素;您不必制作 3D 图形! (提示:如果您将 3D 对象中的所有 z 坐标设置为常数,您将得到一个 2D 对象,对吧!?),在原始 Xlib 中执行此操作完全过于复杂;与此相比,速度损失只是一个小缺点。你说的是“我不想买车,因为我想了解汽车是如何制造的,所以我决定从头开始制造汽车。为此,我使用的不是现代工具,而是石头和污垢。”你不会走得太远。
      • @JeroenD:在现代 OpenGL 中,您必须在着色器中编写旋转和投影矩阵。
      • @MarcusMüller 你告诉人们不要学习和垃圾邮件关于一些没人关心的随机框架是没有任何意义的。
      • @PabloAriel 对不起?我在最后半句提到 SDL。它不是一个真正的高级框架。还有“没人关心”:嗯,这当然不是大牌游戏使用的,而是人们在学习如何在屏幕上制作媒体内容和小型 2D 内容时使用的。而且,游戏开发真的并不是在 X11 本身中完成的,因为 X11 所能贡献的只是一个窗口;游戏的其余部分使用非 X11 方法(OpenGL、Vulkan、...)来绘制东西。我确定你有攻击我的理由?
      猜你喜欢
      • 1970-01-01
      • 2015-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多