Как это сделать: когда мы нажимаем и удерживаем, программу просто делаем один раз? - PullRequest
1 голос
/ 14 марта 2019

Я делаю игровую приставку на C ++, у меня проблема. Когда я нажимаю SPACE , моя машина в моей игре прыгает. Когда я нажимаю и удерживаю клавиатуру, моя машина прыгнет много раз. Я хочу: когда я держу SPACE клавиатуру, моя машина просто прыгает один раз.

Как это сделать?

Я прочитал много тем о GetAsyncKeyState(), но я не знаю, как использовать его для моей игры.

  if ( _kbhit() )

 {

    char key = _getch();

    if ((key == 75) && (car.position.x > 2))
    {
        car.position.x -= 3;
    }
    else if ((key == 77) && (car.position.x < 24))
    {
        car.position.x += 3;
    }
    else if ((key == 32) && (car.position.y > 2))
    {
        car.position.y -= 5;
    }
  }

Ответы [ 2 ]

0 голосов
/ 21 марта 2019

Как заметил @Remy Lebeau, вы можете получить счетчик повторов, установив WH_KEYBOARD hook и отфильтровав нажатую клавишу в KeyboardProc .

Конечно, дляпросто, не нужно устанавливать ловушку, вы можете фильтровать повторяющиеся WM_KEYDOWN сообщения в оконной процедуре , когда вы нажимаете клавишу пробела и удерживаете.Ниже приведен пример, к которому вы можете обратиться:

case WM_KEYDOWN:
    if (wParam == VK_SPACE)
    {           
        if (!((HIWORD(lParam) & 0x4000) || (HIWORD(lParam) & 0x8000)))
        {
            isKeyHold = TRUE; // First time pressed
            OutputDebugString(TEXT("pressed !\n")); 
        }
        else if (isKeyHold && (HIWORD(lParam) & 0x4000))
        {
            OutputDebugString(TEXT("hold !\n")); 
            return 1; // Don't handle the message when the key is pressed and held.
        }
    }
    break;
case WM_KEYUP:
    if (wParam == VK_SPACE && isKeyHold)
    {
        isKeyHold = FALSE; // Clear the isKeyHold flag when release the key.
        OutputDebugString(TEXT("release !\n"));
    }
    break;
0 голосов
/ 15 марта 2019

Ниже приведен пример программного обеспечения одного из возможных способов «отфильтровать» повторяющиеся пробелы из входного потока.

Идея опирается на использование двух потоков.

Thrd1 читает из потока строк с именем ssIn. (Заменяется на cin в вашем коде.)

Thrd1 (фильтр) обнаруживает и сбрасывает последовательные пробелы и отправляет только первый (из нескольких пробелов) в thrd2.

Thrd2 - читает из единственного буфера символов, заполненного thrd1, который никогда не увидит символы пробела.

2 трети синхронизируются парой семафоров (не мьютекс).

В моем примере для моего удобства я использовал свою версию семафора Posix. Я не знаю, есть ли у вас Posix, но я уверен, что вы легко найдете множество примеров семафоров C ++, доступных в Интернете, даже в SO, и большинство из которых использует только функции C ++.


Обратите внимание, что это всего лишь 1 тест ... алфавит с 1 000 000 пробелов, вставленных после 'j'. Это не проверка через. Там, вероятно, будут другие вопросы, чтобы иметь дело с. Я установил жесткую обработку неправильного поведения ввода. Утверждение поможет вам определить проблемы.

"thrd2" представляет вашу привязку к этому примеру. Thrd2 получает отфильтрованный поток.


#include "../../bag/src/dtb_chrono.hh"
using  namespace std::chrono_literals; // support suffixes like 100ms, 2s, 30us
using  std::chrono::duration_cast;

#include <iostream>
using std::cout, std::flush, std::endl;
//using std::cin;

#include <thread>
using  std::thread, std::this_thread::sleep_for;

#include <string>
using std::string;

#include <sstream>
using std::stringstream;

// Posix Process Semaphore, local mode, unnamed, unlocked
#ifndef                 DTB_PPLSEM_HH
#include "../../bag/src/dtb_pplsem.hh"
using DTB::PPLSem_t;
#endif

// string ops
#ifndef                 DTB_SOPS_HH
#include "../../bag/src/dtb_sops.hh"
using DTB::SOps_t;
#endif

#include <cassert>



namespace DTB
{
    class T946_t
   {
   public:
      int operator()(int argc, char* argv[]) // functor entry
         { return exec(argc, argv); }

   private:
      // uses compiler provided default ctor and dtor

      // Posix Process Semaphore, local mode (unnamed, unshared)
      // initial value unlocked
      PPLSem_t th1Sem;
      PPLSem_t th2Sem;
      char     kar = '\n';
      bool     done = false;
      size_t   m_rdy;

      thread*   th1;
      string th1Log;

      thread*   th2;
      string th2Log;

      stringstream ssIn; // debug - replaces cin

      stringstream ss1DR; // th1 delay'd report
      stringstream ss2DR; // th2 delay'd report

      // utilities
      SOps_t    sops;  // string ops - digiComma

      int exec(int , char** )
         {
            // test init: insert a possible user input into ssIn
            init_ssIn();

            int retVal = 0;
            Time_t start_ns = HRClk_t::now();

            th1Sem.lock();  // block until threads are ready
            th2Sem.lock();  // block

            // start ---------vvvvvvvvvvvvvvvvvvv
            th1 = new thread(&T946_t::thrd1, this);
            assert(nullptr != th1);
            while (0 == (m_rdy & 0x01))
               std::this_thread::sleep_for(10ms);

            // start ---------vvvvvvvvvvvvvvvvvv
            th2 = new thread(&T946_t::thrd2, this);
            assert(nullptr != th2);
            while (0 == (m_rdy & 0x02))
               std::this_thread::sleep_for(10ms);

            th1Sem.unlock();

            // spin wait for threads to complete
            while (!done)
            {
               std::this_thread::sleep_for(100ms);
            }

            th1->join();
            th2->join();
            cout << "\n  join()'s complete";

            auto  duration_ns = duration_cast<NS_t>(HRClk_t::now() - start_ns).count();

            cout << "\n  T901_t::exec() duration   "
                 << sops.digiComma(duration_ns) << " ns" << endl;

            // output the delay'd reports
            cout << ss1DR.str() << ss2DR.str() << endl;

            return retVal;
         }

      void init_ssIn()
         {
            ssIn << "abcdefghij";
            for (int i=0; i<1000001; ++i)   ssIn << ' ';
            std::string::size_type k =  ssIn.str().size();
            ssIn << "klmnopqrstuvwxyz";
            //                                          a..j
            cout << "\n  ssIn: '"  << ssIn.str().substr(0, 10)
                 << " ...spaces... " << ssIn.str().substr(k, 16) << "'"
                 << "\n  ssIn.str().size(): "
                 << sops.digiComma(ssIn.str().size()) << endl;
         }

      void thrd1()
         {
            uint64_t th1Count  = 0;
            uint64_t th1Skips  = 0;
            char lkar      = '\0';
            m_rdy |= 0x01;    // sync msg to main

            do {

               getNextKar(lkar); // read from input (ssIn or cin)

               th1Sem.lock();  // wait for thrd2 to give permission
               {
                  if(' ' == lkar)   // current input kar
                  {
                     if(' ' == kar) // previous kar
                     {
                        // filter out back-to-back space chars
                        th1Skips += 1;
                        th1Sem.unlock(); // skip the handshake, no char to send,
                        //                  give self permission-to-proceed
                        continue;
                     }
                  }

                  // else, not a duplicate space
                  th1Count += 1;
                  kar       = lkar; // write to input of thrd2
                  th1Log   += lkar; // log
                  lkar      = ' ';
               }
               th2Sem.unlock(); // give thrd2 permission-to-proceed

               if (ssIn.eof())
               {
                  done = true;
                  break;
               }

            }while(!done);

            ss1DR
               << "\n  th1Count    "  << sops.digiComma(th1Count)
               << "\n  th1Skips    "  << sops.digiComma(th1Skips)
               << "\n  th1Log      "  << th1Log
               << "\n  thrd1 exit  "  << endl;
         }


      // read from ssIn for development
      // read from cin for app
      void getNextKar(char& lkar)
         {
            // ssIn >> lkar; // reads 1 char, but skips multiple blank chars
            // lkar = ssIn.get(); returns an integer (not a char)
            (void)ssIn.get (lkar);

            if(ssIn.fail())
            {
               if(ssIn.eof()) return; // not a fail
               assert(0);             // harsh exit, might want something gentler
            }
         }


      void thrd2()
         {
            uint64_t th2Count = 0;
            m_rdy |= 0x02;    // sync msg to main

            do {
               th2Sem.lock();    // wait for thrd1 to give permission
               char t = kar;
               th1Sem.unlock();  // give permission-to-proceed to thrd1

               // simulate application - no duplicate spaces from input
               th2Log   += t;
               th2Count += 1;
               // end of sim

            }while(!done);

            ss2DR
               << "\n  th2Count   " << sops.digiComma(th2Count)
               << "\n  th2Log     " << th2Log
               << "\n  thrd2 exit " << endl;
         }

   }; // class T946_t

} // namespace DTB


int main(int argc, char* argv[]) { return DTB::T946_t()(argc, argv); }

Вывод выглядит так:

  ssIn: 'abcdefghij ...spaces... klmnopqrstuvwxyz'
  ssIn.str().size(): 1,000,027

  join()'s complete
  T901_t::exec() duration   120,421,582 ns

  th1Count    28
  th1Skips    1,000,000
  th1Log      abcdefghij klmnopqrstuvwxyz 
  thrd1 exit  

  th2Count   28
  th2Log     abcdefghij klmnopqrstuvwxyz 
  thrd2 exit 

Продолжительность 120 мс при вводе 1 млн символов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...