【问题标题】:How to make a timer that counts down from 30 by 1 every second?如何制作一个每秒从 30 倒数 1 的计时器?
【发布时间】:2019-12-17 02:54:39
【问题描述】:

我想制作一个计时器,它每秒显示 30、29 等,然后在有输入时停止。我知道你可以这样做:

    for (int i = 60; i > 0; i--)
    {
        cout << i << endl;
        Sleep(1000);
    }

这将输出 60、59 等。但这不允许在程序运行时进行任何输入。我该如何做才能在倒计时运行时输入内容?

上下文

这不是家庭作业。我正在制作一款文字冒险游戏,其中有一段敌人冲向你,你有 30 秒的时间来决定你要做什么。我不知道如何使计时器能够允许用户在它运行时输入内容。

【问题讨论】:

  • 听起来不错的家庭作业。你试过什么?你遇到了什么问题?您对您的实施有什么疑问?我们如何帮助您完成家庭作业?
  • 这不是家庭作业,抱歉这个不好的问题,我已经解决了,如果您需要更多信息,请告诉我。
  • Fwiw,我不会在没有警告的情况下投反对票。这些反对票不是我的。我推荐一个线程来进行倒计时和显示,并且该线程还应该检查“输入”的标志。我还推荐std::this_thread::sleep_until,而不是Sleep,以保持您的倒计时准确,并使逻辑更简单。
  • 不幸的是,如果不进行一些异步/多线程编程,就无法解决这个问题,因为Sleepcin 都会停止你的程序。看看这个答案,它使用 std::future 和超时来读取用户输入:stackoverflow.com/a/47774984/5023438
  • 我不太明白,我把它放在我的代码中,但它不只是和string input getline(cin, input) cout &lt;&lt; input; 做同样的事情

标签: c++ windows chrono


【解决方案1】:

您的游戏大约每秒 1 帧,因此用户输入是个问题。通常游戏具有较高的帧率,如下所示:

#include <Windows.h>
#include <iostream>

int main() {
    // Initialization
    ULARGE_INTEGER initialTime;
    ULARGE_INTEGER currentTime;
    FILETIME ft;
    GetSystemTimeAsFileTime(&ft);
    initialTime.LowPart = ft.dwLowDateTime;
    initialTime.HighPart = ft.dwHighDateTime;
    LONGLONG countdownStartTime = 300000000; // 100 Nano seconds
    LONGLONG displayedNumber = 31; // Prevent 31 to be displayed

    // Game loop
    while (true) {
        GetSystemTimeAsFileTime(&ft); // 100 nano seconds
        currentTime.LowPart = ft.dwLowDateTime;
        currentTime.HighPart = ft.dwHighDateTime;

        //// Read Input ////
        bool stop = false;
        SHORT key = GetKeyState('S');
        if (key & 0x8000)
            stop = true;

        //// Game Logic ////
        LONGLONG elapsedTime = currentTime.QuadPart - initialTime.QuadPart;
        LONGLONG currentNumber_100ns = countdownStartTime - elapsedTime;
        if (currentNumber_100ns <= 0) {
            std::cout << "Boom!" << std::endl;
            break;
        }
        if (stop) {
            std::wcout << "Stopped" << std::endl;
            break;
        }

        //// Render ////
        LONGLONG currentNumber_s = currentNumber_100ns / 10000000 + 1;
        if (currentNumber_s != displayedNumber) {
            std::cout << currentNumber_s << std::endl;
            displayedNumber = currentNumber_s;
        }
    }

    system("pause");
}

【讨论】:

  • 我不太明白你在说什么
  • 为简单起见:包括conio.h。在Sleep(1000)之前插入if (_getch()=='s')break;,这样当你按下s键时循环可以提前停止。
  • 现在它只在我输入字符时运行
  • @evilhoomans42:答案建议使用non-blocking-call-for-reading-descriptor,因此您可以避免使用该解决方案。
  • @evilhoomans42 抱歉,这是个坏主意。我会重写我的答案。
【解决方案2】:

如果您在 Linux 上运行它,您可以使用经典的 select() 调用。在 while 循环中使用时,您可以等待一个或多个文件描述符的输入,同时还提供一个超时,在该超时之后 select() 调用必须返回。将所有内容封装在一个循环中,您将拥有倒计时和标准输入处理。

https://linux.die.net/man/2/select

【讨论】:

  • 很遗憾我用的是windows
  • winsock2 有选择
  • 什么是 winstock2?
  • 最初由小号推出,它为 Windows 3.0 提供了一个 TCP 堆栈,因此您可以连接到您的拨号服务提供商......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多