Problema con la funzione getch() e kbhit()

di il
9 risposte

Problema con la funzione getch() e kbhit()

Ciao, sto cercando di ricreare il gioco SNAKE
Stavo cercando di dare movimento al serpente, nella funzione di input
void Input()
{
    if( kbhit() )
    {
        switch(getch())
        {
            case 'w':
                dir = TOP;
                break;
            case 'a':
                dir = LEFT;
                break;
            case 'd':
                dir = RIGHT;
                break;
            case 's':
                dir = DOWN;
                break;
            case 'x':
                GameOver = true;
                break;
        }
    }
}
Ma quando runno il programma, è come se nell'esecuzione venisse saltata la funzione void Input() e non capisco perchè.
Mi spiego meglio, il programma non si ferma a chiedere un carattere come dovrebbe, data la funzione kbhit()...

Lascio il codice completo e l'output qui sotto


CODICE
#include <iostream>
#include <conio.h>


using namespace std;

bool GameOver;

const int lunghezza = 20; /// X
const int altezza = 20; /// y

int x, y, FruitX, FruitY, Score;

enum direzione { STOP = 0, TOP, LEFT, RIGHT, DOWN};

direzione dir;

void SetUp()
{
    GameOver = false;
    dir = STOP;
    x = lunghezza / 2;
    y = altezza / 2;
    FruitX = rand() % lunghezza;
    FruitY = rand() % altezza;
    Score = 0;
}
void Draw()
{
    system("cls"); /// clear

    for(int i=0; i<lunghezza+1; i++)
        cout << "#";
    cout << endl;

    for(int i=0; i<altezza; i++)
        {
            for(int c=0; c<lunghezza; c++)
            {
                if(c==0)
                    cout << "#";
                else if(i == y && c == x)
                    cout << "O";
                else if(i == FruitY && c == FruitX)
                    cout << "F";
                else
                    cout << " ";


                if(c == lunghezza - 1)
                    cout << "#" << endl;
            }

        }


    for(int i=0; i<lunghezza+1; i++)
        cout << "#";
    cout << endl;
}
void Input()
{
    if( kbhit() )
    {
        switch(getch())
        {
            case 'w':
                dir = TOP;
                break;
            case 'a':
                dir = LEFT;
                break;
            case 'd':
                dir = RIGHT;
                break;
            case 's':
                dir = DOWN;
                break;
            case 'x':
                GameOver = true;
                break;
        }
    }
}
void Logic()
{
        switch(dir)
        {
        case TOP:   /// sopra
            y++;
            break;

        case LEFT:  /// sinistra
            x--;
            break;

        case RIGHT: /// destra
            x++;
            break;

        case DOWN:  /// sotto
            y--;
            break;

        default:    /// nothing
            break;
    }
}

int main()
{
    SetUp();
    Draw();
    Input();
    Logic();

    return 0;
}
OUTPUT

#####################
#                   #
#                   #
#                   #
#                   #
#                   #
#                   #
#                   #
#F                  #
#                   #
#                   #
#         O         #
#                   #
#                   #
#                   #
#                   #
#                   #
#                   #
#                   #
#                   #
#                   #
#####################

Process returned 0 (0x0)   execution time : 0.245 s
Press any key to continue.
Ps. non ci sono ne errori, ne warnings segnalati dal compilatore

9 Risposte

  • Re: Problema con la funzione getch() e kbhit()

    Ciao, il problema è che kbhit() non attende l'inserimento da tastiera, ma va a leggere direttamente dal buffer di input: se ci trova qualcosa ritorna un intero diverso da zero, altrimenti ritorna zero. Quindi prima di
    if(kbhit())
    dovresti prevedere una "pausa" di durata sufficiente affinché l'utente possa premere qualche tasto.

    Noto che stai utilizzando WASD, ma volendo puoi anche sfruttare i tasti freccia classici o quelli del tastierino numerico. I valori di solito sono i seguenti:
    const int UP = 72;
    const int DOWN = 80;
    const int LEFT = 75;
    const int RIGHT = 77;
    Va precisato però che i tasti freccia, come anche altri comandi speciali, inseriscono nel buffer di input due valori, di cui il primo è 0 (se utilizziamo il tastierino numerico) o 224 (se utilizziamo i tasti freccia classici), mentre il secondo è dato dagli abbinamenti sopra riportati.

    Magari lanciando il seguente codice ti sarà tutto più chiaro:
    #include <iostream>
    #include <conio.h>
    #include <ctime>
    
    using namespace std;
    
    const int UP = 72;
    const int DOWN = 80;
    const int LEFT = 75;
    const int RIGHT = 77;
    
    void delay(int ms)
    {
        clock_t goal = ms * CLOCKS_PER_SEC / 1000 + clock();
        while(goal > clock());
    }
    
    int get_input()
    {
        int input;
        return !(input = getch()) || input == 224 ? getch() : input;
    }
    
    int main()
    {
        for(unsigned int i = 0; i < 10; ++i)
        {
            cout << i + 1 << "--> ";
            delay(1300);
            if(kbhit())
            {
                switch(get_input())
                {
                    case LEFT:
                        cout << "LEFT";
                        break;
                    case RIGHT:
                        cout << "RIGHT";
                        break;
                    case UP:
                        cout << "UP";
                        break;
                    case DOWN:
                        cout << "DOWN";
                        break;
                    default:
                        cout << "WRONG INPUT";
                }
            }
            else
            {
                cout << "NO INPUT";
            }
            cout << endl;
        }
    }
    Se hai dubbi chiedi pure!
  • Re: Problema con la funzione getch() e kbhit()

    Ciao, grazie per avermi risposto
    Come tasti preferisco tenere WASD, magari in un futuro implementeró anche tasti freccia, su tuo consiglio ^^
    Ho 2 domande:

    Per caso va bene anche la funzione sleep() di Windows, per fare la pausa?

    C'è una funzione come la kbhit() ma che non prenda il carattere dal buffer e faccia una pausa per chiederlo all'utente?
  • Re: Problema con la funzione getch() e kbhit()

    Dovra pur andare avanti sto serpente senza che nessuno prema il tasto...
  • Re: Problema con la funzione getch() e kbhit()

    SwitchArio ha scritto:


    Per caso va bene anche la funzione sleep() di Windows, per fare la pausa?
    Su windows dovresti utilizzare la funzione Sleep(time_in_ms).

    SwitchArio ha scritto:


    C'è una funzione come la kbhit() ma che non prenda il carattere dal buffer e faccia una pausa per chiederlo all'utente?
    Si può fare, ma come ti ha fatto notare giustamente @Weierstrass non avrebbe molto senso!
  • Re: Problema con la funzione getch() e kbhit()

    su windows dovresti usare sleep(time_in_ms)
    Sì, mi riferivo a quella.
    Dovrei usarla nel main prima della funzione input() o al suo interno prima di kbhit()?
    dovrà pur andare avanti sto serpente
    Ah giusto, non ha senso
  • Re: Problema con la funzione getch() e kbhit()

    SwitchArio ha scritto:


    Dovrei usarla nel main prima della funzione input() o al suo interno prima di kbhit()?
    Dal punto di vista pratico risulta equivalente.
  • Re: Problema con la funzione getch() e kbhit()

    Ciao SwitchArio, sono curioso di sapere se questa soluzione ti ha permesso di risolvere il problema.
    così a colpo d'occhio mi pare che manchi un "game loop" per far funzionare il gioco.

    Nippolo , in caso ci fosse stato un loop del tipo
    
     while(true) {
     	input()
     	draw()
     }
     
    è comunque necessario inserire un delay per kbhit ?
  • Re: Problema con la funzione getch() e kbhit()

    Okay, ho aggiunto un ciclo do-while nel main per far muovere il serpente
    
    int main()
    {
    
        SetUp();
    do{
        Draw();
        Input();
        Logic();
    }while(GameOver!=true);
    
        return 0;
    }
    
    ed adesso funziona
    Non so davvero come ringraziarti ^^
  • Re: Problema con la funzione getch() e kbhit()

Devi accedere o registrarti per scrivere nel forum
9 risposte