返回(\ r)破折号

时间:2018-12-21 21:04:46

标签: c++ windows command-line c++17 cout

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

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天,但没有找到任何东西,请帮帮我。

2 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:0)

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

您最初有这个:

#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。因此,让我们看一下您的类声明/定义;您当前拥有:

#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() { // ... }
};    

这应该修复您的类的界面设计。此处唯一的主要区别是,我默认将Boolean成员变量设置为false,因为通常在首次启动Engine时,该变量当前尚未运行。因此,要解决此问题,我们可以调用将触发此事件的公共运行函数。所以main看起来像这样:

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条件语句和您的类的成员。最初,您默认情况下将此设置为true,但我在代码中没有看到此值被更新的地方。我们不需要更改此成员,但是修复很简单,因为我们可以通过公共接口调用更改此成员。由于我已默认设置您的isGettingInput false;现在,您可以在进入while循环之前在此函数中进行设置。我看到的最后一个问题是,在main's while循环中调用此函数时;该函数从不返回值,并且永远不会使用返回值。


关于cout用户:1201programalarm的bug的实际问题,已经为您解答了很多。只是以为我会为您的代码提供更多帮助。