This is my code with the class for a Gun and a Bullet, where there are functions defined to move, draw and erase each of them.
The problem is in the use of the function kbhit()
, which I call from 2 different parts of the code:
- To make the gun move
- To shoot
Just as I have the code, it doesn't work for me when I try to use it for the shots (commented at the end of the code).
#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;
}
For example, debugging, if you cut the call to kbhit()
from arma.mover()
and paste it just before Sleep(30)
, changing the order of the loop so that it first reads the trigger and then the move, you'll notice that what works fine is the triggers and what fails is the move function of the weapon.
What can I do to fix it? How can I use the function kbhit()
repeatedly?
Using kbhit() and getch() is not the best choice for a game, as they both depend on the keyboard buffer.
Consider this: when you press a key and hold it down, the keyboard driver first sends an occurrence of the character to the buffer, if you hold the key down for more than 250ms (that's configurable, but it's the default), it starts sending one occurrence of the character repeatedly every 100ms.
This is a headache for a game where timing is always of the essence and is the reason the weapon moves the way it does.
@Alvaro's solution doesn't take this problem into account, although it might solve the current problem, it doesn't solve the most important problem: the way you take the keyboard input.
The best approach is to read the state of each key (pressed, not pressed) for each step of the main loop and set a variable that indicates whether the key is pressed or not and then decide what to do. Forget about using the keyboard input buffer.
It is for this reason that there are libraries like XInput, SDL and other similar libraries.
I have modified your program a bit, first I have added a function called
isKeydown
. This function makes use ofGeyKeyState
to know if the key is pressed or not, it is like a photo of the key, it does not use the keyboard buffer. This is a simple way to do it, but remember there are entire libraries dedicated to live input.Then modify the function
Pistola::mover
as follows:Finally I modified the part where you shoot the bullet.
And this is the result... As you can see, it behaves like a normal game, where when you press a key it responds intuitively.
Note: I have used
GetKeyState
because I see that you include the file "windows.h", and I assume that you are developing it in windows. If you want to port it to another platform, as this function is typical of Windows, it will not work and an appropriate library for the platform must be used.Greetings.
As suggested in this StackOverflow question , what you can do is read the value of
kbhit()
and store it in a variable which will be what you check in both functions, instead of readingkbhit()
twice and losing the buffer with the key that was pressed .So what you would have to do would be:
kbhit()
returns something:kbhit()
and in your codegetch()
and use the variable you created instead.So, you could change things in main (note, I haven't tested the code, it may contain bugs):
That would fix the problem in the , now for the Weapon class
main
method , what you could do is pass it the key value as a parameter and compare to that value:mover