Hi everyone. My name is Zvjezdan Veselinovic and I am a student at Rasmussen College over in New Port Richey, Florida studying Game and Simulation Programming. For my student portfolio, I want to create a "tron-like"/ "snake-like" game called Colors and Explosions.

I have so far arrow key movement. That was no biggie. What I do not have is constant movement while my key is not pressed. Can anyone help me out please? Here is my code. I just want to bounce ideas; not have the project done for me. I can't learn that way.
.
.
.
.

// My "Things_in_background.h" Header file code

#include <iostream>
#include <string>
#include <windows.h> // resize the screen, gotoxy, delay, and so on.
#include <iomanip> // GetAsyncKeyState(), GetKeyState(), and so on.
#include <ctime>
#include <conio.h> // _getch(), _kbhit()

using namespace std;


int gotoxy(int x, int y) // used to place things anywhere in the window
{  
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD point;
    point.X = x-1;
    point.Y = y-1;     
    SetConsoleCursorPosition(hConsole, point);
    return SetConsoleCursorPosition(hConsole, point);
}


void Continue_() { cout << "Press any key to continue... "; _getch(); }
void Space_() { cout << "Press SPACE to continue... "; _getch(); }
void Clear_Line() { gotoxy(5,35); cout << "                                                             " << endl; }

void Up_arrow() { printf("%c", 30); }
void Down_arrow() { printf("%c", 31); }
void Left_arrow() { printf("%c", 17); }
void Right_arrow() { printf("%c", 16); }

void Object() { cout << "&" << endl; }







// my main_program.cpp code


#include "Things_in_background.h"

struct Player_Presses
{
    char up_arrow, down_arrow, left_arrow, right_arrow;
};

int main()
{
    Player_Presses player1;

    char movement;

    int objectx = 2, objecty = 2;



    cout << "Press the Up arrow: "; player1.up_arrow = _getch();

    if(_kbhit())
    {
        player1.up_arrow = _getch(); Up_arrow();

        if(player1.up_arrow == GetAsyncKeyState(VK_UP))
        {
            player1.up_arrow = VK_UP;
        }
    } cout << endl << endl;



    cout << "Press the Down arrow: "; player1.down_arrow = _getch();

    if(_kbhit())
    {
        player1.down_arrow = _getch(); Down_arrow();

        if(player1.down_arrow == GetAsyncKeyState(VK_DOWN))
        {
            player1.down_arrow = VK_DOWN;
        }
    } cout << endl << endl;



    cout << "Press the Left arrow: "; player1.left_arrow = _getch();

    if(_kbhit())
    {
        player1.left_arrow = _getch(); Left_arrow();

        if(player1.left_arrow == GetAsyncKeyState(VK_LEFT))
        {
            player1.left_arrow = VK_LEFT;
        }
    } cout << endl << endl;



    cout << "Press the Right arrow: "; player1.right_arrow = _getch(); 

    if(_kbhit())
    {
        player1.right_arrow = _getch(); Right_arrow(); 

        if(player1.right_arrow == GetAsyncKeyState(VK_RIGHT))
        {
            player1.right_arrow = VK_RIGHT;
        }
    } cout << endl << endl << endl << endl;



    cout << "Your arrows are..." << endl << endl << endl;

    cout << "Up: " << player1.up_arrow << endl << endl;
    cout << "Down: " << player1.down_arrow << endl << endl;
    cout << "Left: " << player1.left_arrow << endl << endl;
    cout << "Right: " << player1.right_arrow << endl << endl;

    Space_(); system("cls");

    system("mode 100,40");

    gotoxy(5,35); Space_();
    Clear_Line();

    gotoxy(objectx,objecty); Object();

    a: gotoxy(5,35); cout << "Press any key to move piece: "; movement = _getch(); 


    if(_kbhit())
    {
        movement = _getch();

        if(movement == player1.up_arrow)
        {
            objecty--;
            gotoxy(objectx, objecty); Object();

            Clear_Line(); goto a;
        }

        if(movement == player1.down_arrow)
        {
            objecty++;
            gotoxy(objectx, objecty); Object();
            Clear_Line(); goto a;
        }

        if(movement == player1.left_arrow)
        {
            objectx--;
            gotoxy(objectx, objecty); Object();
            Clear_Line(); goto a;
        }

        if(movement == player1.right_arrow)
        {
            objectx++;
            gotoxy(objectx, objecty); Object();
            Clear_Line(); goto a;
        }

    } // end of _kbhit()


    return 0;
}

Dani AI

Generated

Short answer: stop waiting for a key every move and run a simple game loop that keeps moving the object each tick while using non‑blocking input only to change the direction. was right to suggest a loop, and ’s post shows the same idea in more detail — the missing piece in your code is separating "input" from "movement" and keeping a current direction state.

The pattern:

  • Keep a direction variable (Up/Down/Left/Right).
  • Enter a timed loop (frame or tick).
  • Each tick: check input non‑blockingly and update the direction only; then move the object one step based on the current direction; draw the new position and sleep for a fixed time.
    Notes on input: arrow keys read with _getch() are extended keys (first return 0 or 224, then the scan code like 72/80/75/77). Alternatively use GetAsyncKeyState(VK_UP) & 0x8000 to test the key state — but don’t compare a captured char to GetAsyncKeyState (that’s the bug in your mapping code). Also avoid calling system("cls") every frame; erase only the old cell and draw the new one to reduce flicker.

Example sketch (keeps direction and moves every tick):

enum Dir { NONE, UP, DOWN, LEFT, RIGHT };
Dir dir = NONE;
int x = 2, y = 2;

while (true) {
    if (_kbhit()) {
        int c = _getch();
        if (c == 0 || c == 224) c = _getch(); // extended arrow
        if (c == 72) dir = UP;
        else if (c == 80) dir = DOWN;
        else if (c == 75) dir = LEFT;
        else if (c == 77) dir = RIGHT;
        else if (c == 27) break; // ESC to quit
    }

    // move according to dir (with bounds checks)
    if (dir == UP) --y;
    else if (dir == DOWN) ++y;
    else if (dir == LEFT) --x;
    else if (dir == RIGHT) ++x;

    // erase previous, draw at (x,y) using gotoxy/Object()
    Sleep(80); // control speed
}

Extra tips: prevent 180° reversal if you implement a snake (ignore opposite-direction input), clamp to screen bounds, and consider a small fixed timestep for consistent speed. If flicker becomes a problem, look into buffering (WriteConsoleOutput) instead of per-cell cursor moves.

Recommended Answers

All 2 Replies

perhaps a while loop around lines 138-168, and change line 138 to use getchar().

and change line 138 to use getchar().

That won't work because getchar() requires a newline to terminate input in the shell. getch() is used because it's a non-blocking input function. This is an appropriate usage of the conio library.

perhaps a while loop around lines 138-168

Yes. Basically you need a game loop that runs forever and handles any input appropriately. For example:

#include <iostream>
#include <Windows.h>

int main()
{
    CONSOLE_SCREEN_BUFFER_INFO info;
    conio::Keys dir = conio::Keys::RIGHT;
    POINT curr = {1, 1};

    GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);

    for (;;) {
        // Clear the current position
        conio::gotoxy(curr.x, curr.y);
        conio::putch(' ');

        // Handle input if necessary
        if (conio::kbhit()) {
            int ch = conio::get_code();

            if (ch == conio::Keys::ESC)
                break;

            switch (ch) {
            case conio::Keys::UP:    dir = conio::Keys::UP;    break;
            case conio::Keys::DOWN:  dir = conio::Keys::DOWN;  break;
            case conio::Keys::LEFT:  dir = conio::Keys::LEFT;  break;
            case conio::Keys::RIGHT: dir = conio::Keys::RIGHT; break;
            }
        }

        // Always adjust the direction to keep things moving
        switch (dir) {
        case conio::Keys::UP:    curr.y = curr.y > 1 ? curr.y - 1 : curr.y;             break;
        case conio::Keys::DOWN:  curr.y = curr.y < info.dwSize.Y ? curr.y + 1 : curr.y; break;
        case conio::Keys::LEFT:  curr.x = curr.x > 1 ? curr.x - 1 : curr.x;             break;
        case conio::Keys::RIGHT: curr.x = curr.x < info.dwSize.X ? curr.x + 1 : curr.x; break;
        }

        // Move to the new position
        conio::gotoxy(curr.x, curr.y);
        conio::putch('@');

        Sleep(100);
    }
}

Note that I'm using a custom conio library for Win32 in that example rather than the conio.h that may or may not be supplied with the compiler. There's still a dependency on Windows, but it's a bit more general than expecting conio.h to be implemented by every Windows compiler. If you're interested, here's the code:

#include <cstdio>
#include <vector>
#include <windows.h>

namespace conio {
    enum Keys {
        ESC   = 27,
        UP    = 256 + 72,
        DOWN  = 256 + 80,
        LEFT  = 256 + 75,
        RIGHT = 256 + 77
    };

    namespace {
        bool unget_avail;  /* True if a character is available for ungetch */
        int unget_char;
    }

    int get_code();
    void gotoxy(int x, int y);
    int kbhit();
    int putch(int c);
    int ungetch(int c);
    int getch();

    int get_code()
    {
        int ch = getch();

        if (ch == 0 || ch == 224)
            ch = 256 + getch();

        return ch;
    }

    void gotoxy(int x, int y)
    {
        COORD pos;

        /* Conio positions are 1-based, but Win32 positions are 0-based */
        pos.X = (short)x - 1;
        pos.Y = (short)y - 1;

        SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
    }

    int kbhit()
    {
        HANDLE sys_stdin = GetStdHandle(STD_INPUT_HANDLE);
        DWORD saved_mode, pending, read;

        /* Save the current mode and switch to raw mode */
        GetConsoleMode(sys_stdin, &saved_mode);
        SetConsoleMode(sys_stdin, 0);

        /* Get the number of pending input events (including key presses) */
        if (!GetNumberOfConsoleInputEvents(sys_stdin, &pending) || !pending)
            return 0;

        std::vector<INPUT_RECORD> info(pending);
        int key_ready = 0;

        /* Peek at and check each pending input event for a key press */
        if (PeekConsoleInput(sys_stdin, &info[0], pending, &read) && read) {
            for (DWORD i = 0; i < read; ++i) {
                if (info[i].EventType == KEY_EVENT && info[i].Event.KeyEvent.bKeyDown) {
                    key_ready = 1;
                    break;
                }
            }
        }

        /* Restore the original console mode */
        SetConsoleMode(sys_stdin, saved_mode);

        return key_ready;
    }

    int putch(int c)
    {
        DWORD written;

        if (WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), &c, 1, &written, 0))
            return EOF;

        return c;
    }

    int ungetch(int c)
    {
        if (unget_avail)
            return EOF; /* Only allow one ungetch at a time */

        unget_avail = true;
        unget_char = c;

        return c;
    }

    int getch()
    {
        if (unget_avail) {
            /* There was a preceding ungetch */
            unget_avail = false;
            return unget_char;
        }
        else {
            HANDLE sys_stdin = GetStdHandle(STD_INPUT_HANDLE);
            DWORD saved_mode, read;
            INPUT_RECORD info;
            int ch = EOF;

            /* Save the current mode and switch to raw mode */
            GetConsoleMode(sys_stdin, &saved_mode);
            SetConsoleMode(sys_stdin, 0);

            /* Read a raw character */
            while (ch == EOF) {
                if (!ReadConsoleInput(sys_stdin, &info, 1, &read) || !read) {
                    ch = EOF;
                    break;
                }
                else {
                    KEY_EVENT_RECORD key = info.Event.KeyEvent;

                    if (info.EventType == KEY_EVENT && key.bKeyDown) {
                        /* Save the current code (may be an escape for extended codes) */
                        ch = key.uChar.AsciiChar;

                        if (ch == 0 || ch == 0xe0) {
                            /* Push the extended code for the next call */
                            ungetch(key.wVirtualScanCode);
                        }
                    }
                }
            }

            /* Restore the original console mode */
            SetConsoleMode(sys_stdin, saved_mode);

            return ch;
        }
    }
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.