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 几乎已经为您解答了。只是想我会用你的代码帮助你多一点。
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 几乎已经为您解答了。只是想我会用你的代码帮助你多一点。