5
\$\begingroup\$

I am trying to make a short text game with c++ to help me learn the language. I have made a version that basically displays texts, waits for an input, once the input is received it displays text, and so on. What I want to do now is make it so that it doesn't wait for the input. Real-time if you will. So certain values keep changing while the player is sitting, and if he sits for too long that game changes in a major way.

My problem is that I can't figure out how to incorporate this in a my game loop. I have a while loop that has a input function, an update function, and a display function. Is this just something I have to do with a wait function?

(I am just using Visual C++ and nothing else).

\$\endgroup\$
  • 2
    \$\begingroup\$ You could spawn a second thread, in addition to the one that's waiting for input. (Then pass info via globals or thread-safe queues, between the console thread and your always-running thread.) Also see keyboard events, stackoverflow.com/questions/2067893/c-console-keyboard-events \$\endgroup\$ – david van brink Jan 19 '15 at 19:12
  • 1
    \$\begingroup\$ @davidvanbrink I think that would be better put as an answer. \$\endgroup\$ – Nic Hartley Jan 20 '15 at 3:39
1
\$\begingroup\$

One approach would be to create a second thread (CreateThread() I think?), in addition to the one that's waiting for input. The second thread could run continuously, check the actual time, update state, and so on. (Probably with a small Sleep, also, so it doesn't pin the CPU at 100%.)

Messages should be passed from your console-reading loop to the game loop in thread-safe queues. Ideally, should disable keystroke echoing on input, and let your game loop do all the printing, so user input display and game output can be controlled as you see fit.

Alternatively, you can have one loop for everything, and poll the keyboard state like described here: https://stackoverflow.com/questions/2067893/c-console-keyboard-events. You'd compare the keyboard state each time through the loop and see which keys have changed, to infer keyup/keydown events.

That SO answer covers some other console-input methods, also, which could work in a one-loop solution.

\$\endgroup\$
  • \$\begingroup\$ I feel that threads are way over-kill for this problem. \$\endgroup\$ – Nathan Goings Jan 20 '15 at 6:11
1
\$\begingroup\$

The Windows API includes "character mode" functions, which deal with consoles and console input at a lower level than the C++ standard library functions. You can make use of these to create a real-time text-based game loop (there are also useful functions in the API for drawing large blocks of characters at a time, which is helpful for creating smooth animation in text-based games).

The main function you'll want to concern yourself with is ReadConsoleInput, which allows you to create a simple game loop as follows:

while(update()) {
  // ...do something...
}

where update() looks like:

bool update () {
    INPUT_RECORD record[kRecordCount];
    DWORD recordCount = 0;

    auto result = ReadConsoleInput(inputHandle, record, kRecordCount, &count);
    for (auto index = 0; index < count ; ++index ) {
        switch(record[index].EventType) {
          // ...
        }
    }

    return trueIfGameIsStillRunning;
}

This is the first step towards a real-time loop. In this basic form, however, update will block if there are no events. There are also some events you will miss (mouse movement events) unless you configure the console input handle accordingly.

For many purposes, the blocking nature of the function is acceptable, but if it isn't, you can have a full real-time loop by using a wait function, supplying the console input handle (inputHandle above) to the function. The wait function will block until input is available or until the specified timeout occurs. You can use, for example, WaitForSingleObject with a very low timeout and check the return value, which indicates if the wait timed out or if the event was signalled. If the former, you process a frame of game updates without player input and wait again (if the latter, you process the player's input).

This method avoids the complexity of threads (although it does involve the complexity of events, which are thread synchronization primitives, so it's not totally trivial), but doesn't require you to set up a full-blown message pump and window (and thus lets you stay in an otherwise pure "text-based" environment you are presumably already familiar with).

\$\endgroup\$
0
\$\begingroup\$

If you are using windows, I would suggest building a simplified GUI with a text-input field.

However, you have an option in the .NET framework to use System.Console.KeyAvailable with System.Console.ReadKey. This is the solution I would use in C# (but also available for C++)

For Windows: The SO questions in this thread suggest using conio.h which is a non-standard C library in certain "MS-DOS Compilers" which include functions similar to KeyAvailable and ReadKey. Such as kbhit and _getch it also lists PeekConsoleInput and ReadConsoleInput which I think are windows.h functions.

For Linux/POSIX systems, I'd suggest ncurses. I haven't used it in a long while, but I enjoyed it.

\$\endgroup\$
  • \$\begingroup\$ Some search queries I ran were "Asychronous console input", "Non-blocking stdin". \$\endgroup\$ – Nathan Goings Jan 20 '15 at 6:13
0
\$\begingroup\$

Instead of using a blocking function such as getline, you will want to get input without blocking.

On Windows, you may implement the message loop and check for keyboard events. You then add the pressed key to your input buffer. When the user presses return you evaluate the input just as you do right now. When the user presses delete, you move back one position in your input buffer, etc.

Wikipedia article about the message loop: https://en.wikipedia.org/wiki/Message_loop_in_Microsoft_Windows

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.