Help with Keyboard input

When I press left, right, up, and down Keys always goes +2 if I change the keys for using direction to any other from the keyboard like e.g. w,a,s,d it's working fine?

EDIT:

I refer to function input(); line 238

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
/// Snake Game ///

// Headers
#include <stdio.h>
#include <conio.h>
#include <windows.h>

#define KEY_UP 72
#define KEY_DOWN 80
#define KEY_LEFT 75
#define KEY_RIGHT 77
#define KEY_ENTER 13
#define KEY_ESCAPE 27

#define ARRAYSIZE(sel) (sizeof(sel) / sizeof(sel[0]))
// SELECT_END last highlighted choice in selections
#define SELECT_END 7

// Global variables
BOOL gameOver;
const int width = 49;
const int height = 15;
int x, y, fruitX, fruitY, score;
int tailX[500], tailY[500];
int nTail;
enum eDirection {STOP, LEFT, RIGHT, UP, DOWN};
enum eDirection dir;

// Functions prototype
void hideCursor();
void menu();
void selector();
void playGame();
void gameControls();
void about();
void setup();
void Draw();
void input();
void logic();

/// Main function
int main()
{
    hideCursor();
    menu();

    return 0;
}
// Main menu
void menu()
{
    int select = 0;
    int x;

    selector(select);

    while((x = getch()))
    {
        if(x == 72)
        {
            select -= 2;
            if(select < 0)
                select = SELECT_END - 1;
            selector(select);
        }
        else if(x == 80)
        {
            select += 2;
            if(select > SELECT_END)
                select = 0;
            selector(select);
        }
        else if(x == 13)
        {
            if(select <= 1)
            {
                playGame();
            }
            else if(select <= 2)
            {
                gameControls();
            }
            else if(select <= 4)
            {
                about();
            }
            else if(select == 6)
            {
                printf("\n\n\n\n\n\n\n\t\t\t       Exiting Game");
                Sleep(1500);
                system("cls");
                exit(0);
            }
        }
    }
}
// Draw menu
void selector(unsigned int select)
{
    const char *selection[] =
    {
        "\n\n\n\n\n\t\t\t     >  PLAY GAME",
        "\n\n\n\n\n\t\t\t        play game",
        "\n\t\t\t     >  GAME CONTROLS",
        "\n\t\t\t        game controls",
        "\n\t\t\t     >  ABOUT",
        "\n\t\t\t        about",
        "\n\t\t\t     >  QUIT GAME",
        "\n\t\t\t        quit game",
    };

    unsigned int i;

    system("cls");
    printf("\n\n\n\n\t\t\t ~~~~~~ SnAkE GaMe ~~~~~~\n");
    printf("\n\n\n\t\t\t    M A I N    M E N U");

    for(i = 0; i < ARRAYSIZE(selection); i += 2)
    {
        if(i == select)
            printf("%s\n", selection[i]);
        else
            printf("%s\n", selection[i + 1]);
    }
}
// Where game start
void playGame()
{
    setup();
    while(!gameOver)
    {
        Draw();
        input();
        logic();
        Sleep(10);
    }
}
// Game controls
void gameControls()
{
    system("cls");
    printf("\n\n\n\n\t\t\t ~~~~~~ SnAkE GaMe ~~~~~~\n");
    printf("\n\n\n\tGame controls using keyboard arrows\n");
    printf("\n\n\n\t\t\t   LEFT\n");
    printf("\n\t\t\t   RIGHT\n");
    printf("\n\t\t\t   UP\n");
    printf("\n\t\t\t   DOWN\n");
    printf("\n\t\t\t   ESC KEY to EXIT game\n\n\n");
    printf("\n\tPress any key to return Main menu");
    getch();
    menu();
}
// About
void about()
{
    system("cls");
    printf("\n\n\n\n\t\t\t ~~~~~~ SnAkE GaMe ~~~~~~\n");
    printf("\n\n\n\n\n\t      Created by:\t\t\tMe");
    printf("\n\n\n\n\n\t        Free for use      2020 - 11 September");
    printf("\n\n\n\n\n\n\t\t\t      Version 1.00");
    printf("\n\n\n\n\n\n\n\t\t    Press any key to return main menu");
    getch();
    menu();
}
// Hide cursor
void hideCursor()
{
    HANDLE ConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO info;
    info.dwSize = 100;
    info.bVisible = FALSE;
    SetConsoleCursorInfo(ConsoleHandle, &info);
}
//
void setup()
{
    gameOver = FALSE;
    dir = STOP;
    x = width / 2;
    y = height / 2;
    fruitX = rand() % width;
    fruitY = rand() % height;
    score = 0;
}
//
void Draw()
{
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD Position;

    Position.X = 0;
    Position.Y = 0;

    SetConsoleCursorPosition(hOut, Position);

    printf("\n\n\t      ~~~~~~ SnAkE GaMe ~~~~~~\n\n");

    for(int i = 0; i < width + 2; i++)
        printf("#");
    printf("\n");

    for(int i = 0; i < height; i++)
    {
        for(int j = 0; j < width; j++)
        {
            if(j == 0)
            printf("#");
            if(i == y && j == x)
                printf("O");
            else if(i == fruitY && j == fruitX)
                printf("$");
            else
            {
                BOOL print = FALSE;
                for(int k = 0; k < nTail; k++)
                {
                    if(tailX[k] == j && tailY[k] == i)
                    {
                        printf("o");
                        print = TRUE;
                    }
                }
                if(!print)
                printf(" ");
            }

            if(j == width - 1)
                printf("#");
        }
        printf("\n");
    }
    for(int i = 0; i < width + 2; i++)
        printf("#");
    printf("\n");
    printf("\nAuthor: Me    Press ESC to Main menu      Score %d\n", score);
}
//
void input()
{
    if(kbhit())
    {
        switch(getch())
        {
        case KEY_LEFT:
            dir = LEFT;
            break;
        case KEY_RIGHT:
            dir = RIGHT;
            break;
        case KEY_UP:
            dir = UP;
            break;
        case KEY_DOWN:
            dir = DOWN;
            break;
        case KEY_ESCAPE:
            printf("\n\n\n\t\t  Returning to menu");
            Sleep(1500);
            gameOver = TRUE;
            menu();
        }
    }
}
//
void logic()
{
    int prevX = tailX[0];
    int prevY = tailY[0];
    int prev2X, prev2Y;
    tailX[0] = x;
    tailY[0] = y;

    for (int i = 1; i < nTail; i++)
    {
        prev2X = tailX[i];
        prev2Y = tailY[i];
        tailX[i] = prevX;
        tailY[i] = prevY;
        prevX = prev2X;
        prevY = prev2Y;
    }

    switch(dir)
    {
    case LEFT:
        x--;
        break;
    case RIGHT:
        x++;
        break;
    case UP:
        y--;
        break;
    case DOWN:
        y++;
        break;
    default:
        break;
    }

    if(x >= width)
    {
            x = 0;
    }
    else if(x < 0 )
    {
        x = width - 1;
    }
    if(y >= height)
    {
        y = 0;
    }
    else if(y < 0 )
    {
             y = height - 1;
    }
    if(x == fruitX && y == fruitY)
        {
            score += 1;
            fruitX = rand() % width;
            fruitY = rand() % height;
            nTail++;
        }

    for(int i = 0; i < nTail; i++)
    {
        if(tailX[i] == x && tailY[i] == y)
        {
            printf("\n\n\n\n\n\n\t\t\t\tGame Over");
            Sleep(1000);
            system("cls");
            printf("\n\n\n\n\n\n\n\n\n\n\n\t\t\t    Returning to menu");
            Sleep(1500);
            gameOver = TRUE;
            menu();
        }
    }
}
Last edited on
When using getch() (which should be _getch() for Windows), the 'special' keys generate 2 chars when pressed. For eg, left arrow key generates the two chars 224 75, right generates 224 77. For your input routine, you need to check if getch() returns 224 and if it is then get another char.

Note that some keys generate first 224 and some generate first 0 (eg F1).

PS. In menu(), why check against a number and not a defined constant as you do in input()?
Last edited on
Ohhh thanks man.. I understand now.

One more question: after the game runs for the first time, when pressing ESC the variables don't reset, so if the second time you hit Play game the program uses the old variables.. How can I do that, because this is bad, I mean user can play only one time and then exit program and run it again?
when ESC is pressed, gameOver is set TRUE, but you are calling menu() again without first terminating the current execution of menu() - infinite menu() recursion! If you remove menu() from input(), then when ESC is pressed then playgame() will exit which returns control to menu(). So in menu() consider:

1
2
3
4
5
if(select <= 1)
            {
                playGame();
                selector(select);
            }


- or something like this.

Last edited on
Okay seeplus what I changed is I add another _getch() for the 'special' keys and now they are working, but I have the ESC key at the end of the Input(); function that generates 0 so now I have to press twice ESC to brake :\.

And i changed:

1
2
3
4
5
else if(select <= 2)
            {
                gameControls();
                selector(select); 
            }

not only.. but to every element in the menu, and woking just fine.

and I was thinking to your question before:

PS. In menu(), why check against a number and not a defined constant as you do in input()?


do ou mean the
int select
?
Last edited on
 
 if(x == 72)


becomes:

 
if (x == KEY_UP)


etc...
Ahhh.. OK understood .. changed to key_up, key_down and key_enter.

Still now I changed:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void input()
{
    if(_kbhit())
    {
        _getch(); //added another char here
        switch(_getch())
        {
        case KEY_LEFT:
            dir = LEFT;
            break;
        case KEY_RIGHT:
            dir = RIGHT;
            break;
        case KEY_UP:
            dir = UP;
            break;
        case KEY_DOWN:
            dir = DOWN;
            break;
        case KEY_ESCAPE:
            printf("\n\n\n\t\t  Returning to menu");
            Sleep(1500);
            gameOver = TRUE;
    }
}


but I have the KEY_ESCAPE which generates first 0, so now I have to press 2 times ESC to take effect.. and now because I add another _getch() If you play and press any other key will pause the game.. maybe I have to add a default case ?
Last edited on
Only if the first _getch() returns a 0 or a 224 do you do another _getch()

1
2
3
4
5
6
char ch = _getch();
if (ch == 0 || ch == 224)
    ch = _getch();

switch(ch) {
...

Last edited on
Seems correctly.. I change it to:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void input()
{
    if(_kbhit())
    {
        char ch = _getch();
        if(ch == 0 || ch == 224)
            ch = _getch();

        switch(ch)
        {
        case KEY_LEFT:
            dir = LEFT;
            break;
        case KEY_RIGHT:
            dir = RIGHT;
            break;
        case KEY_UP:
            dir = UP;
            break;
        case KEY_DOWN:
            dir = DOWN;
            break;
        case KEY_ESCAPE:
            printf("\n\n\n\t\t  Returning to menu");
            Sleep(1500);
            gameOver = TRUE;
        }
    }
}


but no effect, I mean is more like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void input()
{
    if(_kbhit())
    {
        switch(_getch())
        {
        case KEY_LEFT:
            dir = LEFT;
            break;
        case KEY_RIGHT:
            dir = RIGHT;
            break;
        case KEY_UP:
            dir = UP;
            break;
        case KEY_DOWN:
            dir = DOWN;
            break;
        case KEY_ESCAPE:
            printf("\n\n\n\t\t  Returning to menu");
            Sleep(1500);
            gameOver = TRUE;
            menu();
        }
    }
}
Last edited on

Only if the first _getch() returns a 0 or a 224 do you do another _getch()

1
2
3
4
5
6
char ch = _getch();
if (ch == 0 || ch == 224)
    ch = _getch();

switch(ch) {
...





I tested now ch has to be an int not an char to make this work..

Again thanks for help seeplus.. I remain with one problem I have mentioned up that my game isn't really working 100% because it uses the old variables so I guess I have to figure out how to reset it/..
Last edited on
Sorry, my bad. I didn't test it. The return type of _getch() is int. On Windows, the default for char is signed, so the range is -128 to +127 - so would never equal 224. Doh!!

When one game is finished, playgame() exits and now re-displays the menu. If you choose to play game again, then playgame() is entered and setup() is executed. If some variables are not being reset properly, then they probably should be in setup().


Last edited on
Finally I solve the problem.. I had to reset the snake tail int the logic(); function:

1
2
3
4
5
6
7
8
9
10
11
12
13
 for(int i = 0; i < nTail; i++)
    {
        if(tailX[i] == x && tailY[i] == y)
        {
            printf("\n\n\n\n\n\n\t\t\t\tGame Over");
            Sleep(500);
            system("cls");
            printf("\n\n\n\n\n\n\n\n\n\n\n\t\t\t    Returning to menu");
            Sleep(1500);
            gameOver = TRUE;
            nTail = 0;
        }
    }


that's the variable that wasn't reset after the game was over.
In the setup(); it only reset the position of the snake head to the center the score to 0 and 'dir' = STOP to not move. Now it's working perfectly :D

Next move I'm gonna achieve in a file the highest score.. lol.. sounds like a joke but I'm really enjoy programming.. :)

Until next time Cheers !!
Last edited on
Topic archived. No new replies allowed.