ASCII DOS 游戏 - 渲染方法

发布于 2024-09-11 14:49:57 字数 1047 浏览 2 评论 0原文

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

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

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

我不想使用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 fps。

我想也许我应该尝试将 RenderInterval 设置为 0.0 以查看性能是否有所提高...但事实并非如此。我(渲染间隔为 0.0)的最大帧速率约为 18-20fps。

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

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

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

I'm writing an old school ASCII DOS-Prompt game. Honestly I'm trying to emulate ZZT to learn more about this brand of game design (Even if it is antiquated)

I'm doing well, got my full-screen text mode to work and I can create worlds and move around without problems BUT I cannot find a decent timing method for my renders.

I know my rendering and pre-rendering code is fast because if I don't add any delay()s or (clock()-renderBegin)/CLK_TCK checks from time.h the renders are blazingly fast.

I don't want to use delay() because it is to my knowledge platform specific and on top of that I can't run any code while it delays (Like user input and processing). So I decided to do something like this:

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

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

Which should in "theory" work just fine. The problem is that when I run this code (setting the RenderInterval to 0.0333 or 30fps) I don't get ANYWHERE close to 30fps, I get more like 18 at max.

I thought maybe I'd try setting the RenderInterval to 0.0 to see if the performance kicked up... it did not. I was (with a RenderInterval of 0.0) getting at max ~18-20fps.

I though maybe since I'm continuously calling all these clock() and "divide this by that" methods I was slowing the CPU down something scary, but when I took the render and ballLogic calls out of the if statement's brackets and set RenderInterval to 0.0 I get, again, blazingly fast renders.

This doesn't make sence to me since if I left the if check in, shouldn't it run just as slow? I mean it still has to do all the calculations

BTW I'm compiling with Borland's Turbo C++ V1.01

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

流殇 2024-09-18 14:49:57

最佳的游戏体验通常是通过与显示器的垂直回扫同步来实现的。除了提供计时之外,这还将使游戏在屏幕上运行得更流畅,至少如果您有连接到计算机的 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));
  }

The best gaming experience is usually achieved by synchronizing with the vertical retrace of the monitor. In addition to providing timing, this will also make the game run smoother on the screen, at least if you have a CRT monitor connected to the computer.

In 80x25 text mode, the vertical retrace (on VGA) occurs 70 times/second. I don't remember if the frequency was the same on EGA/CGA, but am pretty sure that it was 50 Hz on Hercules and MDA. By measuring the duration of, say, 20 frames, you should have a sufficiently good estimate of what frequency you are dealing with.

Let the main loop be someting like:

  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));
  }
感情旳空白 2024-09-18 14:49:57
clock()-renderTimer > RenderInterval * CLOCKS_PER_SEC

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

clock()-renderTimer > RenderInterval * CLOCKS_PER_SEC

would compute a bit faster, possibly even faster if you pre-compute the RenderInterval * CLOCKS_PER_SEC part.

他不在意 2024-09-18 14:49:57

我明白了为什么它没有立即渲染,我创建的计时器很好,问题是实际的clock_t只能精确到0.054547XXX左右,所以我只能以18fps渲染。我解决这个问题的方法是使用更准确的时钟......这是一个完全不同的故事

I figured out why it wasn't rendering right away, the timer that I created is fine the problem is that the actual clock_t is only accurate to .054547XXX or so and so I could only render at 18fps. The way I would fix this is by using a more accurate clock... which is a whole other story

新一帅帅 2024-09-18 14:49:57

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

clock()/CLOCKS_PER_SEC-renderTimer/CLOCKS_PER_SEC > RenderInterval

写不是更高效吗:

( clock() - renderTimer ) > RenderInterval

我在除法中看到的第一个问题是你不会从中得到一个实数,因为它发生在两个 long 之间整数。第二个问题是,乘以 RenderInterval * CLOCKS_PER_SEC 会更有效,这样就可以摆脱它,简化操作。

添加括号可以使其更易读。也许通过简化这个公式,你会更容易地发现问题所在。

What about this: you are substracting from x (=clock()) y (=renderTimer). Both x and y are being divided by CLOCKS_PER_SEC:

clock()/CLOCKS_PER_SEC-renderTimer/CLOCKS_PER_SEC > RenderInterval

Wouldn't it be mor efficiente to write:

( clock() - renderTimer ) > RenderInterval

The very first problem I saw with the division was that you're not going to get a real number from it, since it happens between two long ints. The secons problem is that it is more efficiente to multiply RenderInterval * CLOCKS_PER_SEC and this way get rid of it, simplifying the operation.

Adding the brackets gives more legibility to it. And maybe by simplifying this phormula you will get easier what's going wrong.

紫﹏色ふ单纯 2024-09-18 14:49:57

正如您在最近的问题中发现的那样,您受到 CLOCKS_PER_SEC 的限制,该值仅为 18 左右。每个离散时钟值都会获得一帧,这就是您被限制为 18fps 的原因。

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

As you've spotted with your most recent question, you're limited by CLOCKS_PER_SEC which is only about 18. You get one frame per discrete value of clock, which is why you're limited to 18fps.

You could use the screen vertical blanking interval for timing, it's traditional for games as it avoids "tearing" (where half the screen shows one frame and half shows another)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文