怎么做:当我们按住时,程序只做一次?

问题描述 投票:1回答:2

我正在使用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;
    }
  }
c++ winapi
2个回答
0
投票

下面我有一个示例软件,可以从输入流中“过滤”重复的空间字符。

这个想法依赖于两个线程的使用。

Thrd1从名为ssIn的字符串流中读取。 (在代码中替换为cin。)

Thrd1(过滤器)检测并丢弃背靠背空间字符,并仅将第一个(多个空间字符)发送到thrd2。

Thrd2 - 从thrd1填充的单个char缓冲区中读取,它永远不会看到背靠背的空格字符。

2个thrds由一对信号量(不是互斥量)同步。

在我的例子中,为了方便起见,我使用了我的Posix信号量版本。我不知道你是否有Posix,但我相信你很容易在网上找到很多可用的C ++信号量,即使在SO中也是如此,大多数只使用C ++功能。


请注意,这只是一个测试......在'j'之后注入1,000,000个空格的字母表。这不是一个彻头彻尾的考验。可能还有其他问题需要处理。我已经安装了对输入错误行为的严厉处理。断言将帮助您识别问题。

“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 

对于1百万个字符输入,持续时间为120毫秒。


0
投票

正如@Remy Lebeau所指出的,您可以通过安装WH_KEYBOARD hook来获得重复计数,并过滤在KeyboardProc中按下的键。

当然,简单来说,没有必要安装一个钩子,当你按空格键并按住时,你可以在WM_KEYDOWN中过滤重复的window procedure消息。以下是您可以参考的示例:

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;
© www.soinside.com 2019 - 2024. All rights reserved.