这是我的代码,其中包含 Gun 和 Bullet 类,其中定义了用于移动、绘制和擦除它们中的每一个的函数。
问题在于函数的使用kbhit()
,我从代码的两个不同部分调用它:
- 让枪动起来
- 拍摄
就像我有代码一样,当我尝试将它用于拍摄时它对我不起作用(在代码末尾注释)。
#include <iostream>
#include <windows.h>
#include <conio.h>
#include <list>
#include <stdio.h>
using namespace std;
void gotoxy(int x, int y){
HANDLE hCon;
hCon = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pw;
pw.X = x;
pw.Y = y;
SetConsoleCursorPosition(hCon, pw);
}
class Pistola{
private:
int x, y;
public:
Pistola(int _x, int _y): x(_x), y(_y){}
void pintar();
void borrar();
void mover();
int getX(){return x;}
int getY(){return y;}
};
void Pistola::pintar(){
gotoxy(x,y); printf("( )==:");
gotoxy(x,y+1); printf("||");
}
void Pistola::borrar(){
gotoxy(x,y); printf(" ");
gotoxy(x,y+1); printf(" ");
}
void Pistola::mover(){
if(kbhit()){ // <--- Aca estoy usando para mover
borrar();
char tecla = getch();
if(tecla == 'i') y--;
if(tecla == 'k') y++;
if(tecla == 'j') x--;
if(tecla == 'l') x++;
pintar();
}
}
class Bala{
private:
int x, y;
public:
Bala(int _x, int _y): x(_x), y(_y){}
void pintar();
void mover();
void borrar();
int getX(){return x;}
int getY(){return y;}
};
void Bala::pintar(){
gotoxy(x,y); printf("*");
}
void Bala::mover(){
gotoxy(x,y); printf(" ");
if( x < 70 ) x++;
gotoxy(x,y); printf("*");
}
void Bala::borrar(){
gotoxy(x,y); printf(" ");
}
int main()
{
Pistola arma(10,10);
bool game_over = false;
list<Bala*> B;
list<Bala*>::iterator it;
arma.pintar();
while( !game_over ){
/// El problema esta en que si uso la funcion khbit() para hacer mover el armar, no me funcion cuando
/// la intento usar para los disparos, si corta arma.mover() y lo pega justo antes de Sleep(30) notara
/// que lo que funiona bien son los disparos y lo que falla es la funcion mover del arma.
arma.mover();
if( kbhit() ){ // <--- Aca estoy usando para disparar
char tecla = getch();
if( tecla == 'a'){
B.push_back(new Bala(arma.getX()+7, arma.getY()));
}
}
for( it = B.begin(); it != B.end(); it++){
(*it)->mover();
if( (*it)->getX() >= 70 ){
(*it)->borrar();
delete (*it);
it = B.erase(it);
}
}
Sleep(30);
}
return 0;
}
例如,调试时,如果您将调用剪切到kbhit()
fromarma.mover()
并将其粘贴到之前Sleep(30)
,更改循环的顺序以便它首先读取触发器然后移动,您会注意到正常工作的是触发器,而失败的是是武器的移动功能。
我能做些什么来修复它?如何kbhit()
重复使用该功能?
使用 kbhit() 和 getch() 并不是游戏的最佳选择,因为它们都依赖于键盘缓冲区。
考虑一下:当您按下一个键并按住它时,键盘驱动程序首先将出现的字符发送到缓冲区,如果您按住键超过 250 毫秒(这是可配置的,但它是默认值),它开始发送每 100 毫秒重复出现一次字符。
对于一个时间总是至关重要的游戏来说,这是一个令人头疼的问题,这也是武器以它的方式移动的原因。
@Alvaro 的解决方案没有考虑到这个问题,虽然它可能会解决当前的问题,但它并没有解决最重要的问题:你接受键盘输入的方式。
最好的方法是读取主循环每一步的每个键的状态(按下、未按下),并设置一个变量来指示该键是否被按下,然后决定要做什么。忘记使用键盘输入缓冲区。
正是出于这个原因,才有了像 XInput、SDL 和其他类似库这样的库。
我对您的程序进行了一些修改,首先我添加了一个名为
isKeydown
. 该功能GeyKeyState
用于知道按键是否被按下,就像按键的照片一样,它不使用键盘缓冲区。这是一种简单的方法,但请记住,有整个库专门用于实时输入。然后修改函数
Pistola::mover
如下:最后我修改了你射击子弹的部分。
这就是结果......正如你所看到的,它的行为就像一个普通的游戏,当你按下一个键时,它会直观地做出反应。
注意:我使用过
GetKeyState
是因为我看到您包含文件“windows.h”,并且我假设您是在 windows 中开发它。如果要将其移植到另一个平台,因为此功能是 Windows 的典型功能,它将无法工作,并且必须使用适合该平台的库。问候。
正如这个StackOverflow 问题中所建议的那样,您可以做的是读取 的值
kbhit()
并将其存储在一个变量中,这将是您在两个函数中检查的内容,而不是读取kbhit()
两次并使用按下的键丢失缓冲区。所以你必须做的是:
kbhit()
返回一些东西:kbhit()
和代码中的引用,getch()
并改用您创建的变量。因此,您可以更改 main 中的内容(注意,我没有测试过代码,它可能包含错误):
这将解决中的问题,现在对于Weapon 类
main
方法,您可以做的是将键值作为参数传递给它并与该值进行比较:mover