Return (\r) 中断计算

Return (\r) breaking cout

std::cout 在我的 keyPressed 字符串中打印额外的字符,可能是因为“\r”,例如,如果 keyPressed =“Right arrow”,当我按下向上箭头时,它打印“keyPressed = Up arrowoww ”,然后,当我再次按下右箭头时,它会再次正常打印“keyPressed = Right arrow”,但是如果我按下除“Right arrow”之外的任何箭头键,它会在末尾打印一些不需要的额外字符

Error example

源代码:

game.cpp

#include "engine.h"
#include <iomanip>

Engine eng;

int main() {
    while (eng.isRunning) {
        eng.getInput();
        std::cout << std::setw(5);
        std::cout << "\r X = " << eng.playerX;
        std::cout << "| Y = " << eng.playerY;
        std::cout << "| KEY = " << eng.keyPressed;
        Sleep(100);
    }
    return 0;
}

engine.h

#ifndef ENGINE_H
#define ENGINE_H

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

class Engine {
public:
    // Game
    bool isRunning = true;
    bool gettingInput = true;

    // Player
    int playerX = 1;
    int playerY = 1;
    char playerModel = 'P';

    // Test / Debug
    std::string keyPressed;

    // Functions
    char getInput() {
        // Gets arrow keys states
        while (this->gettingInput) {
            this->keyPressed = "";
            if (GetAsyncKeyState(VK_RIGHT)) {
                // Right arrow key
                this->playerX++;
                this->keyPressed = "Right arrow";
                break;
            }
            else if (GetAsyncKeyState(VK_LEFT)) {
                // Left arrow key
                this->playerX--;
                this->keyPressed = "Left arrow";
                break;
            }
            else if (GetAsyncKeyState(VK_UP)) {
                // Up arrow key
                this->playerY++;
                this->keyPressed = "Up arrow";
                break;
            }
            else if (GetAsyncKeyState(VK_DOWN)) {
                // Down arrow key
                this->playerY--;
                this->keyPressed = "Down arrow";
                break;
            }
            else if (GetAsyncKeyState(VK_END)) {
                exit(0);
            }
            Sleep(255);
        }
    }
};

#endif

解决此问题的最佳/最简单方法? 我搜索和测试了 3 天,但没有找到任何东西,请帮助我。

由于您要覆盖之前的输出,因此当您打印较短的字符串时,之前输出中的额外字符仍会显示。将 \r 替换为 \n 以查看实际输出的内容。

您可以在键名后输出一些空格,用空格覆盖那些多余的字符并擦除它们。

在查看了您提供的代码后,我确实发现了一些与代码设计有关的问题或疑虑:我将对其进行分解并解释一些我认为可以提高代码质量的内容。我将从您的 main.cpp 开始,然后转到您的引擎 class.

你最初有这个:

#include "engine.h"
#include <iomanip>

Engine eng;

int main() {
    while (eng.isRunning) {
        eng.getInput();
        std::cout << std::setw(5);
        std::cout << "\r X = " << eng.playerX;
        std::cout << "| Y = " << eng.playerY;
        std::cout << "| KEY = " << eng.keyPressed;
        Sleep(100);
    }
    return 0;
}

我看到的第一个主要问题是您在全球范围内声明了 Engine eng。我们可以通过

解决这个问题
#include "engine.h"
#include <iostream>
#include <iomanip>

int main() {
    Engine eng; // declare it here as the first object in main; now it has local
                // scope within main's function and is now in Automatic Storage 
                // instead of Global Storage.
    while( ... ) {
        // ....
    }
    return 0;
};

下一期从main函数中while循环的条件表达式开始。 您目前拥有:

while( engine.isRunning ) { //... }

没关系,但这更多是您的 Engine class's 设计的问题。您在这里提供了一个任何人都可以访问的 public member。那么让我们看看你的 class declaration/definition;您目前拥有:

#ifndef ENGINE_H
#define ENGINE_H

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

class Engine {
public:
    // Game
    bool isRunning = true;
    bool gettingInput = true;

    // Player
    int playerX = 1;
    int playerY = 1;
    char playerModel = 'P';

    // Test / Debug
    std::string keyPressed;

    // Functions
    char getInput() { // ... }
};

#endif

在这里你应该保护你的数据成员并拥有对它们的访问修饰符函数:

#ifndef ENGINE_H
#define ENGINE_H

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

class Engine {
private:
    bool isRunning;
    bool gettingInput;

    // Player
    int playerX;
    int playerY;
    char playerModel;

    // Test / Debug
    std::string keyPressed;

 public:
    Engine() : 
      isRunning( false ),
      isGettingInput( false ),
      playerX( 1 ),
      playerY( 1 ),
      playerModel( 'P' ) 
    {}

    void run() { isRunning = true; // set or call other things here... }

    // Since we protected our members variables by making them private,
    // we now need some access functions to retrieve and modify them.
    bool isActive() const { return isRunning; } // make this const so it doesn't change anything
    void toggleIsActive() { isRunning = !isRunning; }

    bool retrievingInput() const { return isGettingInput; }
    void toggleRetrievingInput() { isGettingInput = !isGettingInput; } 

    int getPlayerX() const { return playerX; }
    void setPlayerX( int newX ) { playerX = newX; }

    int getPlayerY() const { return playerY; }
    void setPlayerY( int newY ) { playerY = newY; }

    // set both in one function call
    void setPlayerPosition( int newX, int newY ) {
        playerX = newX;
        playerY = newY;
    }

    char getPlayerModel() const { return playerModel; }
    // don't know if you want to change this: uncomment if you do
    // void setPlayerModel( char c ) { playerModel = c; }

    std::string& getPressedKey() const { return keyPressed; }

    char getInput() { // ... }
};    

这应该可以修复您 class 的界面设计。这里唯一的主要区别是我默认将 Boolean 成员变量设置为 false,因为通常当您第一次启动 Engine 时,它目前还没有 运行ning。所以为了解决这个问题,我们可以调用一个 public 运行 函数来触发它。所以主要看起来像这样:

int main () {
    Engine eng;
    eng.run(); // this now starts the engine sets the flag to true

    while (...) { //... }

    return 0;
}

但是,我也看到了您的 Engine's getInput() 功能中的一些问题,所以让我们看一下。

char getInput() {
    // Gets arrow keys states
    while (this->gettingInput) {
        this->keyPressed = "";
        if (GetAsyncKeyState(VK_RIGHT)) {
            // Right arrow key
            this->playerX++;
            this->keyPressed = "Right arrow";
            break;
        }
        else if (GetAsyncKeyState(VK_LEFT)) {
            // Left arrow key
            this->playerX--;
            this->keyPressed = "Left arrow";
            break;
        }
        else if (GetAsyncKeyState(VK_UP)) {
            // Up arrow key
            this->playerY++;
            this->keyPressed = "Up arrow";
            break;
        }
        else if (GetAsyncKeyState(VK_DOWN)) {
            // Down arrow key
            this->playerY--;
            this->keyPressed = "Down arrow";
            break;
        }
        else if (GetAsyncKeyState(VK_END)) {
            exit(0);
        }
        Sleep(255);
    }
}

第一部分是 while loop's 条件语句和您的 class 成员。最初您默认将此设置为 true,但我没有在代码中的任何地方看到此值正在更新。我们不需要更改它,但现在修复很简单,因为我们有办法通过 public 接口调用来更改此成员。因为我默认你的 isGettingInput false;您现在可以在进入 while 循环之前在此函数中进行设置。我看到的唯一最后一个问题是,当在 main's while 循环中回调此函数时;此函数从来没有 return 的值,并且 return 的值从未被使用过。


关于 cout 用户的 bug 的实际问题:1201programalarm 几乎已经为您解答了。只是想我会用你的代码帮助你多一点。