简体   繁体   中英

C++ get arrow key press while a thread is running

I am trying to make a snake game in c++. I have a thread that moves the snake's head in the direction that the user specifies with the arrow keys. if I press the up arrow key I need the head to move up and continue moving (this is done by the thread) without me pressing the arrow keys.

The issue is i can't get the keyboard input to work together with the thread, its either one function works or its the other, they can't work together

Keyboard input function:

void moveSnake()
{
    while(true)
    {
        int key = getch();
        switch(key)
        {
        case 72:
        {
              //UP
              break;
        }
        case 80:
        {
              // DOWN
              break;
        }
        case 77:
        {
             // RIGHT
              break;
        }
        case 75:
        {
             // LEFT
              break;
        }
    }
}

Thread function:

void thread_handler()
{
    while(true)
    {
        // Move the snake
        Sleep(500);
    }
}

This is where i create the thread and call the keyboard function

int main()
{
    moveSnake();
    thread t(thread_handler);
    t.join();
    return 0;
}

I have tried

  • putting moveSnake() in a thread
  • executing the thread_handler function without a thread
  • tried to put both functions in a separate thread
  • tried switching the order with all these possible solutions

But none of these worked.

I need a way to get the keycode for the arrow keys while running the thread at the same time

Follow your source code like the compiler would, from top to bottom. Your debugger can help you step through it. You've went into a never ending loop in your main thread. What comes after that doesn't matter because you never get there.

Even if you switch the ordering of things, you've still got a never ending loop, so you cannot join properly after you call it.

You need to read up on some basic threading lessons. Just because you are using threads doesn't mean you can stop worrying about whether loops exit or not. Loops should always have some exit condition.

For your program, I'd assume you'd want to start a thread to handle the input, lock some manner of storage and read key presses. Back in your main thread, you'd probably want to loop until some signal for exit, lock and get the stored key press/command (maybe use a thread safe queue?), and react to it.

Here is a very simple and naive example:

#include <mutex>
#include <thread>
#include <queue>

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

class Application
{
public:

    void Run()
    {
        // Start input thread
        if (m_inputThread.joinable())
        {
            Shutdown();
        }

        auto thread = std::thread(std::bind(&Application::InputThreadProc, this));
        m_inputThread.swap(thread);

        while (!m_shutdown)
        {
            // React to the queued input, including checking for shutdown
            // I'm just going to ignore the complex issue of timing
            std::this_thread::sleep_for(std::chrono::milliseconds(33));
            std::lock_guard<std::mutex> lock(m_mutex);
            if( !m_keysPressed.empty() )
            {  
                auto key = m_keysPressed.front();
                m_keysPressed.pop();

                switch (key)
                {
                case 75:
                    m_shutdown = true;
                default:
                    std::cout << "I saw a key: " << key << std::endl;
                    break;
                }
            }
        }

        Shutdown();
    }

private:

    std::mutex      m_mutex;
    std::queue<int> m_keysPressed;
    bool            m_shutdown = false;
    std::thread     m_inputThread;

    void Shutdown()
    {
        if (m_inputThread.joinable())
        {
            m_inputThread.join();
        }
    }

    void InputThreadProc()
    {
        while (!m_shutdown)
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(33));
            std::lock_guard<std::mutex> lock(m_mutex);

            // OS Specific. Better means of getting localized input exist.
            // Also, timing is an issue. Is the key pressed when we are trying to read.
            // Input is a complex topic and many libraries for it exist
            m_keysPressed.emplace(_getch());
        }
    }
};

int main()
{
    Application application;
    application.Run();

    return 0;
}

Change the order of your main to

int main()
{
    thread t(thread_handler);
    moveSnake();
    t.join();
    return 0;
}

this way the thread is started before your input loop (which is an endless loop). Make sure you leave the t.join() at the end.

With this said, you need to create a method that both the thread and input loop exit. Currently both are infinite loops.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM