我试图用C ++做一个简单的游戏(Pong)。游戏是一个"控制台游戏"。 我只是写了部分代码,但现在我发现了一个麻烦: 我创建了一个_getch()和_kbhit()函数
int _getch( ) {
struct termios oldt, newt;
int ch;
tcgetattr( STDIN_FILENO, &oldt );
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newt );
ch = getchar();
tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
return ch;
}
int _kbhit() {
static const int STDIN = 0;
static bool initialized = false;
if (! initialized) {
termios term;
tcgetattr(STDIN, &term);
term.c_lflag &= ~ICANON;
tcsetattr(STDIN, TCSANOW, &term);
setbuf(stdin, NULL);
initialized = true;
}
int bytesWaiting;
ioctl(STDIN, FIONREAD, &bytesWaiting);
return bytesWaiting;
}
但是当我按下一个键时,它会打印在控制台上。我怎么能阻止这个?
我的完整代码:
#include <iostream>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <sys/select.h>
#include <stropts.h>
#include <sys/ioctl.h>
using namespace std;
void gotoxy(int x,int y){
printf("\x1b[%d;%df",y,x);
}
int _getch( ) {
struct termios oldt, newt;
int ch;
tcgetattr( STDIN_FILENO, &oldt );
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newt );
ch = getchar();
tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
return ch;
}
int _kbhit() {
static const int STDIN = 0;
static bool initialized = false;
if (! initialized) {
// Use termios to turn off line buffering
termios term;
tcgetattr(STDIN, &term);
term.c_lflag &= ~ICANON;
tcsetattr(STDIN, TCSANOW, &term);
setbuf(stdin, NULL);
initialized = true;
}
int bytesWaiting;
ioctl(STDIN, FIONREAD, &bytesWaiting);
return bytesWaiting;
}
class Ball{
public:
};
class Game{
public:
void __init(){
this->pointL = 0;
this->pointR = 0;
}
void addScore(char side){
if(side == 'l') pointL++;
else if(side == 'r') pointR++;
else cout<< "ERROR-2";
return;
}
unsigned int getScore(char side){
if(side == 'l') return this->pointL;
else if (side == 'r') return this->pointR;
else return 0;
}
bool isPlaying(){
return this->playing;
}
bool stop(){
this->playing = false;
return true;
}
private:
unsigned int pointL, pointR;
bool playing;
};
class Player{
public:
int pos[5][2];
int maxX, maxY;
void __init(int maxX, int maxY, char side){
//create matrix with all cords of block of wall (r and l)
this->maxX = maxX;
this->maxY = maxY;
if(side == 'l')
for(int i = 0; i<5; i++){
pos[i][0] = 2;
pos[i][1] = 2+i;
gotoxy(pos[i][0],pos[i][1]);
cout<< "|";
}
else if(side == 'r')
for(int i = 0; i<5; i++){
pos[i][0] = maxX-4;
pos[i][1] = 2+i;
gotoxy(pos[i][0],pos[i][1]);
cout<< "|";
}
else
cout<<"ERRORE-1";
}
void moveUp(){
gotoxy(pos[4][0],pos[4][1]);
cout<< " ";
for(int i = 0; i<5; i++){
pos[i][1] = (pos[i][1] == 0)?pos[i][1]:pos[i][1]-1;
gotoxy(pos[i][0],pos[i][1]);
cout<< "|"; //solid rectangle
}
}
void moveDown(){
gotoxy(pos[4][0],pos[4][1]);
cout<< " ";
for(int i = 0; i<5; i++){
pos[i][1] = (pos[i][1] == this->maxY)?pos[i][1]:pos[i][1]+1;
gotoxy(pos[i][0],pos[i][1]);
cout<< "|"; //solid rectangle
}
}
};
int main(){
int a;
Game game;
Player pl1,pl2;
cout<< "Ridimensiona la finestra come meglio preferisci, quando hai fatto, premi un tasto per continuare";
_getch();
struct winsize size;
ioctl( 0, TIOCSWINSZ, (char *) &size );
printf("\e[2J\e[H");
pl1.__init(size.ws_row, size.ws_col, 'l');
pl2.__init(size.ws_row, size.ws_col, 'r');
//asap menu here
cout<< "TEST: " << size.ws_row;
char key;
while(game.isPlaying()){
if(_kbhit()){
key = _getch();
switch(key){ //when i press that keys, it's printed on terminal, how prevent?
case 'w':
pl1.moveUp();
break;
case 's':
pl2.moveDown();
break;
case 'q':
game.stop();
break;
}
}
}
return 0;
}
答案 0 :(得分:3)
这是一个不响应击键但是将字符写入stderr的程序。如果您使用g++ -o t t.cpp
进行编译,那么您可以使用例如./t 2>somefile
,因此将stderr重定向到somefile
。
在第二个终端中,您可以在每次击键后执行cat somefile
以控制程序写入的内容。 (警告:less somefile
没有在我的cygwin安装上工作,因为文件增长只出现在较少的块中(我告诉它等待输入,按下&#34; F&#34;)。 / p>
由于所有击键被转发到控制程序Control-C或其他通过其控制终端向运行程序发送信号的装置不起作用。你必须从不同的终端杀死它。
基本思想是read()在原始模式下阻塞,直到输入可用,因此不需要单独的kbhit()
。
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
using namespace std;
int main()
{
struct termios oldt;
if( tcgetattr( 0, &oldt ) )
{
fprintf(stderr, "Error getting term attribs\n");
}
cfmakeraw(&oldt);
if( tcsetattr(0, TCSANOW, &oldt) )
{
fprintf(stderr, "Error setting term attribs\n");
}
char inp;
while(true)
{
int bytesRead = read(0, &inp, 1);
if( bytesRead <= 0)
{
fprintf(stderr, "oops, bytes read return val is %d\n", bytesRead);
}
else
{
write(2, &inp, 1);
}
}
}
答案 1 :(得分:0)
您可以使用:
#include <iostream>
#include <stdexcept>
#include <termios.h>
#include <unistd.h>
// A class for mofdifying the behavour of a terminal.
class Terminal
{
// Types
// =====
public:
typedef speed_t speed_type;
// Terminal
// ========
public:
// Initialize the terminal file descriptor and store the attributes of the terminal.
Terminal(int fd)
: m_fd(fd), m_restore(get(fd))
{}
// Restore the orignal attributes of the terminal
~Terminal() {
set(m_fd, m_restore, false);
}
Terminal(const Terminal&) = delete;
const Terminal& operator = (const Terminal&) = delete;
int fd() const { return m_fd; }
void restore() { set(m_fd, m_restore); }
protected:
// Get attributes of a terminal
static termios get(const int fd) {
termios attributes;
if(tcgetattr(fd, &attributes) < 0) {
throw std::runtime_error("Terminal");
}
return attributes;
}
// Set attributes of a terminal
static void set(const int fd, const termios& attributes, bool exception = true) {
if(tcsetattr(fd, TCSANOW, &attributes) < 0 && exception) {
throw std::runtime_error("Terminal");
}
}
// Set attributes of a terminal
static void set(const int fd, int action, const termios& attributes, bool exception = true) {
if(tcsetattr(fd, action, &attributes) < 0 && exception) {
throw std::runtime_error("Terminal");
}
}
private:
int m_fd;
termios m_restore;
};
// A class for mofdifying the input behavour of a terminal.
class StdInputTerminal : public Terminal
{
// Constants
// =========
public:
enum Attributes {
Blocking = 0x01,
Echo = 0x02
};
// Static
// ======
public:
// Clear available input in std::cin
static void clear() {
termios attributes = disable_attributes(Blocking);
while(std::cin)
std::cin.get();
std::cin.clear();
set(fileno(stdin), attributes);
}
// StdInputTerminal
// ================
public:
// Initialize with 'stdin'
StdInputTerminal()
: Terminal(fileno(stdin))
{}
public:
// Disable attributes specified by any combination of Attributes flags
void disable(unsigned flags) { disable_attributes(flags); }
// Disable blocking
void disable_blocking() { disable_attributes(Blocking); }
protected:
// Set attributes of the terminal
static termios disable_attributes(unsigned flags) {
const int fd = fileno(stdin);
termios attributes = get(fd);
termios a = attributes;
if(flags & Blocking) {
a.c_lflag &= ~ICANON;
a.c_cc[VMIN] = 0;
a.c_cc[VTIME] = 0;
}
if(flags & Echo) {
a.c_lflag &= ~ECHO;
}
set(fd, a);
return attributes;
}
};
// Sample Usage
// ============
int kbhit() {
StdInputTerminal terminal;
terminal.disable(StdInputTerminal::Blocking | StdInputTerminal::Echo);
int result = 0;
char c;
if( ! std::cin.get(c))
std::cin.clear();
else
{
result = c;
std::cin.unget();
}
return result;
}
int getch() {
StdInputTerminal terminal;
terminal.disable(StdInputTerminal::Blocking | StdInputTerminal::Echo);
char result = 0;
while(true) {
std::cin.get(result);
if(std::cin.eof()) {
std::cin.clear();
usleep(100000);
}
else break;
}
if(std::cin.fail()) {
std::cin.clear();
result = 0;
}
return result;
}
// Test
// ====
int main()
{
std::cout << "Enter a single sample character: ";
char c;
std::cin.get(c);
std::cin.unget();
if(kbhit()) {
int ch = getch();
std::cout << "Entered character: " << char(ch);
if(kbhit()) {
int ch = getch();
std::cout << " Newline " << char(ch);
if(kbhit()) {
std::string line;
getline(std::cin, line);
std::cout << "\nToo many sample characters: " << line << '\n';
}
}
}
}
(请原谅不完整的课程,你是实验性的)
答案 2 :(得分:-2)
使用getpass()
:
getpass()函数打开进程的控制终端,写入 对该设备的以null结尾的字符串提示,禁用回显, 读取一串字符直到下一个换行符或EOF, 恢复终端状态并关闭终端。