首页 > 解决方案 > C ++如何在不擦除屏幕的情况下闪烁单行文本?

问题描述

操作系统:Windows 10 编译器: Visual Studio 2017 C++ 版本: 14,显然

我正在为学校制作文字冒险游戏。在某些屏幕上,我希望文本段落以闪烁的文本行结束,上面写着“按“ENTER”继续”,带有动画省略号,当用户按“Enter”时,该行被清除,下一段跟随。我写了一些我认为可以工作的代码,但是那条特定的行并没有从

Press ENTER to continue

随着时间的推移。这是最小的“工作”示例:

    #include <iostream>
    #include <string>
    #include <chrono>
    #include <thread>;

    using namespace std;
    using namespace this_thread;     // sleep_for, sleep_until
    using namespace chrono_literals; // ns, us, ms, s, h, etc.
    using chrono::system_clock;

    //class to implement UI methods
    class UI {
    public:
        UI() {}

        void printTitleCard() {
            cout << "+---------------------------+" << endl;
            cout << "|    \"A Text Adventure\"     |" << endl;
            cout << "|            by             |" << endl;
            cout << "|            Me             |" << endl;
            cout << "+---------------------------+" << endl << endl;
        }

        void intro() {
            cout << "Your mother warned you about getting into cars with strangers." << endl;
            cout << "She didn't say anything about vans, true, and it did have a" << endl;
            cout << "friendly moustache on the front bumper, but you knew the risks." << endl;
            cout << "Now you're waking up in the wilderness with no wallet and no clues..." << endl;
            pressEnterToContinue();
            cout << "...and there's something on your shoes." << endl;
        }

        void pressEnterToContinue() {
        //This prompts the user to press "ENTER" to continue
        while (1) {
            string str = "Press ENTER to continue";
            cout << str;
            sleep_until(system_clock::now() + 0.25s); // wait a quarter-second
            cout << string(str.length(), '\b'); // delete printed line
            //repeat
            str += ".";
            cout << str;
            sleep_until(system_clock::now() + 0.25s); // wait a quarter-second
            cout << string(str.length(), '\b'); // delete printed line
            //repeat
            str += ".";
            cout << str;
            sleep_until(system_clock::now() + 0.25s); // wait a quarter-second
            cout << string(str.length(), '\b'); // delete printed line
            //repeat
            str += ".";
            cout << str;
            sleep_until(system_clock::now() + 0.25s); // wait a quarter-second
            cout << string(str.length(), '\b'); // delete printed line
            if (cin.get()) break;
        }
        cin.ignore();
    }
};

    void main()
    {   
        UI ui;
        //Title Card
        ui.printTitleCard();

        //Intro
        ui.intro();
    }

不仅文本没有“动画”,我还必须按两次 ENTER 才能继续下一行。

我在这里问这个问题是因为我已经做了将近一个小时的研究,知道我之前已经尝试过解决这个问题,并且提供的唯一解决方案是

有人可以帮我(也许是互联网的其他人)关闭关于这个主题的书吗?在这种情况下工作的解决方案可以在许多其他情况下工作。永远感谢您的时间。

:请记住,这是我的项目的一个彻底精简的版本,用于隔离这个问题。

更新:我已成功使其“闪烁”。我只需要 break 条件来工作,因为现在它只是阻止 while 循环重新开始(莫名其妙):

#include <iostream>
#include <string>
#include <chrono>
#include <thread>

using namespace std;
using namespace this_thread;     // sleep_for, sleep_until
using namespace chrono_literals; // ns, us, ms, s, h, etc.
using chrono::system_clock;

//class to implement UI methods
class UI {
public:
    UI() {}

    void printTitleCard() {
        cout << "+---------------------------+" << endl;
        cout << "|    \"A Text Adventure\"    |" << endl;
        cout << "|            by             |" << endl;
        cout << "|            Me             |" << endl;
        cout << "+---------------------------+" << endl << endl;
    }

    void intro() {
        cout << "Your mother warned you about getting into cars with strangers." << endl;
        cout << "She didn't say anything about vans, true, and it did have a" << endl;
        cout << "friendly moustache on the front bumper, but you knew the risks." << endl;
        cout << "Now you're waking up in the wilderness with no wallet and no clues..." << endl;
        pressEnterToContinue();
        cout << "...and there's something on your shoes." << endl;
    }

void pressEnterToContinue() {
        //This prompts the user to press "ENTER" to continue
        while (1) {
            string str = "Press ENTER to continue";
            cout << str;
            sleep_until(system_clock::now() + 0.5s); // wait a half-second
            cout << string(str.length(), '\b'); // go to front of line
            //repeat
            str += ".";
            cout << str;
            sleep_until(system_clock::now() + 0.5s); // wait a half-second
            cout << string(str.length(), '\b'); // go to front of line
            //repeat
            str += ".";
            cout << str;
            sleep_until(system_clock::now() + 0.5s); // wait a half-second
            cout << string(str.length(), '\b'); // go to front of line
            //repeat
            str += ".";
            cout << str;
            sleep_until(system_clock::now() + 0.5s); // wait a half-second
            cout << string(str.length(), '\b'); // go to front of line
            cout << string(str.length(), ' ');; //print spaces
            cout << string(str.length(), '\b'); // go to front of line
            sleep_until(system_clock::now() + 0.5s); // wait a half-second
            //if (cin.get()) break;
        }
        cin.ignore();
    }
};

void main()
{   
    UI ui;
    //Title Card
    ui.printTitleCard();

    //Intro
    ui.intro();
}

UPDATE2:我现在有异步方法,但我无法获得“ENTER”键来一致地注册。退出 while 循环总是需要至少 2 次尝试,我不知道这是否是因为内存问题(那不是很可悲)、 的固有缺陷或我的逻辑错误。这是我的最小工作示例。我是如此接近,请提供完整的解决方案!

#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <future>
//#include <C:/Program Files/boost/boost_1_71_0/boost/atomic.hpp>

using namespace std;
using namespace this_thread;     // sleep_for, sleep_until
using namespace chrono_literals; // ns, us, ms, s, h, etc.
using chrono::system_clock;

//class to implement UI methods
class UI {
public:
    UI() {}

    void printTitleCard() {
        cout << "+---------------------------+" << endl;
        cout << "|    \"A Text Adventure\"     |" << endl;
        cout << "|            by             |" << endl;
        cout << "|            Me             |" << endl;
        cout << "+---------------------------+" << endl << endl;
    }

    void intro() {
        cout << "Your mother warned you about getting into cars with strangers." << endl;
        cout << "She didn't say anything about vans, true, and it did have a" << endl;
        cout << "friendly moustache on the front bumper, but you knew the risks." << endl;
        cout << "Now you're waking up in the wilderness with no wallet and no clues..." << endl;
        pressEnterToContinue();
        cout << "...and there's something on your shoes." << endl;
    }

    void pressEnterToContinue() {

        using namespace std::literals;
        string str;

        auto f = std::async(std::launch::async, [str] {
            string userStr;
            getline(cin, userStr);
            if (userStr == "") {
                cout << string(str.length(), '\b'); // go to front of line
                cout << string(str.length(), ' ');; //print spaces
                cout << string(str.length(), '\b'); // go to front of line
                cin.ignore();
                return;}
        });

        while (f._Is_ready()==false/*f.wait_for(1s) != std::future_status::ready*/) {
            str = "Press ENTER to continue";
            cout << str;
            sleep_until(system_clock::now() + 0.5s); // wait a half-second
            cout << string(str.length(), '\b'); // go to front of line
            //repeat
            str += ".";
            cout << str;
            sleep_until(system_clock::now() + 0.5s); // wait a half-second
            cout << string(str.length(), '\b'); // go to front of line
            //repeat
            str += ".";
            cout << str;
            sleep_until(system_clock::now() + 0.5s); // wait a half-second
            cout << string(str.length(), '\b'); // go to front of line
            //repeat
            str += ".";
            cout << str;
            sleep_until(system_clock::now() + 0.5s); // wait a half-second
            cout << string(str.length(), '\b'); // go to front of line
            cout << string(str.length(), ' ');; //print spaces
            cout << string(str.length(), '\b'); // go to front of line
            sleep_until(system_clock::now() + 0.5s); // wait a half-second
        }
    }
};

void main()
{   
    UI ui;
    //Title Card
    ui.printTitleCard();

    //Intro
    ui.intro();
}

标签: c++animationio

解决方案


我知道了。这解决了 Windows 平台上 C++ 的 3 个常见问题解答(我不认为第二个是新颖或需要的解决方案):

  • 如何在不清除屏幕的情况下使一行文本“闪烁”
  • 如何删除和覆盖控制台行
  • 如何从连续运行的异步循环中运行和逃脱。

这是我最小的实际工作示例:

编辑:好的,所以仍然存在一个缺陷:如果您尝试再次运行 pressEnterToContinue() 函数,则循环仅运行一次。这可能与我如何设置循环条件有关。将不胜感激反馈。

#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <future>

using namespace std;
using namespace this_thread;     // sleep_for, sleep_until
using namespace chrono_literals; // ns, us, ms, s, h, etc.
using chrono::system_clock;

//class to implement UI methods
class UI {
public:
    UI() {}

    void printTitleCard() {
        cout << "+---------------------------+" << endl;
        cout << "|    \"A Text Adventure\"     |" << endl;
        cout << "|            by             |" << endl;
        cout << "|            Me             |" << endl;
        cout << "+---------------------------+" << endl << endl;
    }

    void intro() {
        cout << "Your mother warned you about getting into cars with strangers." << endl;
        cout << "She didn't say anything about vans, true, and it did have a" << endl;
        cout << "friendly moustache on the front bumper, but you knew the risks." << endl;
        cout << "Now you're waking up in the wilderness with no wallet and no clues..." << endl;
        pressEnterToContinue();
        cout << "...and there's something on your shoes." << endl;
    }

    void pressEnterToContinue() {

        using namespace std::literals;
        string str;

        auto f = std::async(std::launch::async, [str] {
            string userStr;
            getline(cin, userStr);
            if (userStr == "\r") {
                cout << string(str.length(), '\b'); // go to front of line
                cout << string(str.length(), ' ');; //print spaces
                cout << string(str.length(), '\b'); // go to front of line
                return;}
        });

        while (f._Is_ready()==false/*f.wait_for(1s) != std::future_status::ready*/) {
            str = "Press ENTER to continue";
            cout << str;
            sleep_until(system_clock::now() + 0.5s); // wait a half-second
            cout << string(str.length(), '\b'); // go to front of line
            //repeat
            str += ".";
            cout << str;
            sleep_until(system_clock::now() + 0.5s); // wait a half-second
            cout << string(str.length(), '\b'); // go to front of line
            //repeat
            str += ".";
            cout << str;
            sleep_until(system_clock::now() + 0.5s); // wait a half-second
            cout << string(str.length(), '\b'); // go to front of line
            //repeat
            str += ".";
            cout << str;
            sleep_until(system_clock::now() + 0.5s); // wait a half-second
            cout << string(str.length(), '\b'); // go to front of line
            cout << string(str.length(), ' ');; //print spaces
            cout << string(str.length(), '\b'); // go to front of line
            sleep_until(system_clock::now() + 0.5s); // wait a half-second
        }
    }
};

int main()
{   
    UI ui;
    //Title Card
    ui.printTitleCard();

    //Intro
    ui.intro();
    return 0;
}

推荐阅读