【问题标题】:Return (\r) breaking cout返回 (\r) 中断 cout
【发布时间】:2018-12-21 21:04:45
【问题描述】:

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

Error example

源码:

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

【问题讨论】:

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


    【解决方案1】:

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

    你可以在你的键名后面输出一些空格来用空格覆盖那些多余的字符并删除它们。

    【讨论】:

      【解决方案2】:

      查看您提供的代码后,我确实发现了一些与代码设计有关的问题或顾虑:我将对其进行分解并解释一些我认为可以提高代码质量的事情。我将从您的 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,但我在代码中的任何位置都没有看到此值正在更新。我们不需要更改它,但修复很简单,因为我们可以通过公共接口调用更改此成员。因为我默认你的isGettingInputfalse;您现在可以在进入 while 循环之前在此函数中设置它。我看到的唯一最后一个问题是,当在main's while 循环中回调此函数时;此函数从不返回值,并且从不使用返回值。


      至于您对cout 用户的错误的实际问题:1201programalarm 几乎已经为您回答了这个问题。只是想我会用你的代码帮助你更多。

      【讨论】:

      • 我知道 Stack Overflow 告诉人们不要在 cmets 中说“谢谢”,但是,谢谢伙计,真的帮助了我,并且会帮助我编写未来的代码。
      • @Pero 我知道,但我也这样做,但不是直接这样做。我会这样说:“我非常感谢您的反馈或积极的批评,因为它只会帮助我成为更高效的程序员、软件工程师。”
      • @Pero 他们还说我不应该像上面那样给出答案。我不介意尽我所能提供帮助。它甚至可以帮助我提高自己的技能。它也可以作为未来使用的一个很好的参考。反正我是这样做的,因为我是纯自学的。当我第一次开始学习编程时,我的第一门语言是 C 和 C++ 的组合。那是在 90 年代末和 2000 年代初,当时信息和资源仍然有限。是的,互联网是一轮;但是在拨号上网和高速互联网开始的时代,大多数网站都是文本......
      • @Pero 继续...即使是图片也需要一段时间才能加载到老式 SVGA 显示器(前纯平屏幕)上。如果你有一台 17 或 19 英寸的显示器,它们的尺寸也很小,因为大多数显示器只有 9 到 15 英寸……分辨率太可怕了……如果你有 1280 x 960,你做得很好。视频非常罕见,您不能只是流式传输它们,您必须下载它们才能观看并希望您能够播放它。像这样的网站和 youtube 还没有出现,大多数在线教程都是文本,只有一些无法编译的示例......
      • @Pero 继续......他们没有解释如何使用链接器或调试器,唯一真正可用的东西主要是关于语言的语法和语言的概念.我学会了艰难的道路,现在我已经快 20 年了,我仍在学习,因为 C++ 语言正在发展。我专门为 3D 图形渲染、动画、物理模拟等编程,我必须自学 DirectX 和 OpenGL,现在我正在尝试学习 CUDA 和 Vulkan。学习 C++ 很难,但如果你能坚持下去;这是非常值得的!
      猜你喜欢
      • 2014-06-29
      • 1970-01-01
      • 2012-06-14
      • 2016-09-08
      • 2016-07-22
      • 2011-11-08
      • 1970-01-01
      • 1970-01-01
      • 2014-09-24
      相关资源
      最近更新 更多