【问题标题】:ASCII DOS Games - Rendering methodsASCII DOS 游戏 - 渲染方法
【发布时间】:2011-03-19 13:12:18
【问题描述】:

我正在编写一个老式的 ASCII DOS 提示游戏。老实说,我正在努力模仿 ZZT 来了解更多关于这个品牌的游戏设计(即使它已经过时了)

我做得很好,我的全屏文本模式可以工作,我可以毫无问题地创建世界和四处移动,但我找不到合适的渲染计时方法。

我知道我的渲染和预渲染代码很快,因为如果我不添加任何 delay()s 或 (clock()-renderBegin)/CLK_TCK 检查来自 time.h 的渲染速度非常快。

我不想使用 delay(),因为它是特定于我的知识平台的,最重要的是,当它延迟时我无法运行任何代码(如用户输入和处理)。所以我决定做这样的事情:

do {
    if(kbhit()) {
        input = getch();
        processInput(input);
    }

    if(clock()/CLOCKS_PER_SEC-renderTimer/CLOCKS_PER_SEC > RenderInterval) {
        renderTimer = clock();
        render();
        ballLogic();
    }
}while(input != 'p');

“理论上”应该可以正常工作。问题是,当我运行这段代码(将 RenderInterval 设置为 0.0333 或 30fps)时,我没有得到接近 30fps 的任何地方,我得到的最大速度更像是 18。

我想也许我会尝试将 RenderInterval 设置为 0.0 以查看性能是否有所提升……但没有。我(RenderInterval 为 0.0)达到最高 ~18-20fps。

虽然我可能是因为我不断调用所有这些时钟()和“除以那个”方法,我正在减慢 CPU 速度,但当我从 if 语句的括号中取出渲染和 ballLogic 调用时将 RenderInterval 设置为 0.0 我再次获得了超快的渲染速度。

这对我来说没有意义,因为如果我离开 if 签入,它不应该运行同样慢吗?我的意思是它仍然需要做所有的计算

顺便说一句,我正在使用 Borland 的 Turbo C++ V1.01 进行编译

【问题讨论】:

  • 你和我,咖啡馆。 (#throwstar seek)。 @Parad0x13:如果您不介意离开 DOS,我编写了一个库来在 SDL 支持的任何平台上模拟这种图形样式:libfake437.googlecode.com
  • 如果你存储'clock()'的结果并分配存储的值,你将保存对它的调用(最快的代码是你不调用的代码),它将是更准确(否则你会失去你第一次调用'clock()'之间的时间,做所有的数学和处理分支)。即使您不再最大限度地使用 CPU,这种准确性的损失也会使游戏运行速度比您想要的慢。 (编辑:哈哈,刚刚看到这个日期,哦)

标签: c++ ascii render dos turbo-c++


【解决方案1】:

最好的游戏体验通常是通过与显示器的垂直回扫同步来实现的。除了提供时间之外,这还可以让游戏在屏幕上运行更流畅,至少如果您将 CRT 显示器连接到计算机。

在 80x25 文本模式下,垂直回扫(在 VGA 上)发生 70 次/秒。我不记得 EGA/CGA 上的频率是否相同,但我很确定 Hercules 和 MDA 上的频率是 50 Hz。通过测量例如 20 帧的持续时间,您应该对正在处理的频率有足够好的估计。

让主循环类似于:

  while (playing) {
     do whatever needs to be done for this particular frame
     VSync();
  }

  ...  /* snip */

  /* Wait for vertical retrace */
  void VSync() {
    while((inp(0x3DA) & 0x08));
    while(!(inp(0x3DA) & 0x08));
  }

【讨论】:

    【解决方案2】:

    我知道为什么它没有立即渲染,我创建的计时器很好,问题是实际的clock_t 只精确到 .054547XXX 左右,所以我只能以 18fps 渲染。我解决这个问题的方法是使用更准确的时钟......这是另一回事

    【讨论】:

      【解决方案3】:

      正如您在最近的问题中所发现的那样,您受到 CLOCKS_PER_SEC 的限制,它只有大约 18 个。每个离散的时钟值都会得到一帧,这就是限制为 18fps 的原因。

      您可以使用屏幕垂直消隐间隔进行计时,这对于游戏来说是传统的,因为它可以避免“撕裂”(一半屏幕显示一帧,另一半显示另一帧)

      【讨论】:

        【解决方案4】:

        这个怎么样:你从 x (=clock()) y (=renderTimer) 中减去。 x 和 y 都除以 CLOCKS_PER_SEC:

        clock()/CLOCKS_PER_SEC-renderTimer/CLOCKS_PER_SEC > RenderInterval
        

        这样写会不会更有效率:

        ( clock() - renderTimer ) > RenderInterval
        

        我看到的第一个除法问题是你不会从中得到一个实数,因为它发生在两个长整数之间。 secons问题是RenderInterval * CLOCKS_PER_SEC相乘效率更高,这样就可以去掉它,简化操作。

        添加括号使其更易读。也许通过简化这个公式,你会更容易出错。

        【讨论】:

        • 我尝试了这些公式优化,但仍然得到相同的结果。
        • 如果你强制 RenderInterval = 1 怎么办?
        【解决方案5】:
        clock()-renderTimer > RenderInterval * CLOCKS_PER_SEC
        

        如果您预先计算 RenderInterval * CLOCKS_PER_SEC 部分,计算速度会更快,甚至可能更快。

        【讨论】:

        • 感谢您的回复,我看到了优化。即使有了它,问题仍然存在。刚试了一下
        • 编译器对循环进行各种优化,这可能会产生特殊性(尤其是如果它们包含分支) - 尝试在这两种情况下查看生成的代码。事实上,处理器做了一些类似的工作(查找分支预测)。
        • 我检查了预处理器,但找不到启用了哪些优化
        猜你喜欢
        • 2014-10-24
        • 1970-01-01
        • 1970-01-01
        • 2018-03-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多