如何使用 xlib 创建游戏循环

Jer*_*enD 5 c++ linux x11 xlib

我正在尝试为 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

JvO*_*JvO 6

您没有看到任何内容的原因是您忽略了 X 事件循环。您所做的只是向 X 服务器发送数据,但 X 服务器无法进行通信。

您必须设置一个循环,从队列中读取 XEvent 并分派 cq 进行处理。就像是:

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
  }
}
Run Code Online (Sandbox Code Playgroud)

不过,这可以与无限循环结合起来。

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


Mar*_*ler 2

直接与 Xlib 通信是 90 年代早期的事(请注意:在过去 20 年里,没有人这样做过,除非他是框架设计师!)。

你是对的,循环像素来更新屏幕上的像素速度非常慢。这就是为什么几乎所有现代 GUI 框架都使用自己的 Xbuffer,它们只是绘制并指示 X 进行渲染。

作为对你的方法的评论:在原始 X 上进行游戏开发没有任何意义,因为有更有利可图、性能更好、更易于使用、小型、经过良好测试的库。以SDL为例。

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

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

  • 感谢您的答复。我决定不使用 OpenGL 等库,因为我想了解一些有关这些库背后的数学知识。我的意思是我打算手动编程旋转矩阵、投影等,而不是仅仅调用 OpenGL 函数。您的意思是出于 fps 的原因我不应该这样做,或者有没有办法在没有这样的库的情况下完成这项工作? (2认同)