【问题标题】:How to execute method code only once although called every frame尽管每帧都调用一次,但如何只执行一次方法代码
【发布时间】:2017-02-02 13:12:34
【问题描述】:

我正在编写一个游戏,并且在我的 InputHandler 类中我编写了一个 getKeyState 方法,它返回一个特定的键是否被按下(布尔值)。

在某些情况下的问题是,无论我多么努力,按下一个键总是需要“很长时间”,以至于我的 getKeyState 方法多次返回 true,因为它在每一帧都被调用。

当我需要特定的动作只执行一次时,我必须这样写:

int n = 0; // global variable

(...)

// --- inside a class method which is called every frame as well: ---

if (Input.getKeyState(key))
{
    n++;

    if (n == 1)
    {
        // specific behaviour
    }
}
else
{
    n = 0;
}

我现在的问题是:如何在 InputHandler 类中的方法中实现这一点。我不想每次都声明一个计数器变量,我需要一个“仅按下一次键”的方法。我只想打电话:

if (Input.isKeyPressedAndTriggerOnlyOncePls())

【问题讨论】:

  • 每帧仅一次,还是每个对象每帧一次?
  • 输入是单例。为了简单起见,我没有把它写在这里。

标签: c++ events input triggers keyboard


【解决方案1】:

编辑: 您需要检查按键,然后检查取消按键。

bool keyPressed = false;

bool InputHandler(){
   if(keyPresed == false){
      if( key is being pressed ){
         keyPressed = true;
         return true;
      }
   }
   else{
      if( key is not being pressed ){
         keyPressed = false;
      }
       return false;
   }
}

编辑2: 如果您真的希望 InputHandler() 进行检查,您可以为每个调用者设置一个标志数组并为每个调用者提供一个 ID,然后如果调用 InputHandler(),则按下键并且 ID 的标志为 false,则返回 true , 否则返回 false,但每次未按下键时都必须重置所有标志。

所以前面的代码看起来是这样的:

bool arrayReset = true;
bool pressUsed[Number of callers] = {0};

bool InputHandler(int id){
   if(key is being pressed){
      if( pressUsed[id] == false){
         pressUsed[id] = true;
         arrayReset = false;
         return true;
      }
   }
   else if( key is not being pressed && arrayReset == false){
         arrayReset = true;
         set pressUsed[] all elements to false;
   }

return false;
}

编辑3: 如果您多次调用该方法但在同一个循环中,您可以执行以下操作:

bool keyPressed = false;

bool InputHandler(){
   if(key is being pressed && keyPresed == false)
     return true;
}


bool InputHandlerWithChange(){
   if(keyPresed == false){
      if( key is being pressed ){
         keyPressed = true;
         return true;
      }
   }
   else{
      if( key is not being pressed ){
         keyPressed = false;
      }
       return false;
   }
}

每次需要检查是否按下某个键时调用 InputHandler()。在循环结束时或在最后一个需要检查按键的地方调用 InputHandlerWithChange(),这样当按键被按下时,所有调用者都会收到 true,并且在按键未被按下之前将停止接收 true。

【讨论】:

  • 这也是我的第一个解决方案,但问题是 InputHandler 类是一个单例,当我从代码中的不同位置多次调用该方法时,只有我调用的第一个会返回 true .
  • 您必须以某种方式检查呼叫者是否已使用此按键。最简单的为什么会为每次调用设置一个标志(类似于您示例中的计数器),如果 getKeyState() 返回 true 并且标志为 false ,请执行您的操作,然后将标志设置为 true,如果 getKeyState() 返回 true 并且标志为false 什么也不做,如果 getKeyState() 返回 false 设置标志为 false。
  • 谢谢你这是一个很好的答案!
【解决方案2】:

一种方法是创建一个带有静态数据成员的父类。然后,您可以创建从该类继承的输入处理程序。

// Main parent class
class InputHandlerParent {
public:
    InputHandlerParent() {} ;
    virtual bool isKeyPressedAndTriggerOnlyOncePls()
    {
        return keypressed;
    }
    virtual void setKeyPressed()
    {
        keypressed = true ;
        std::cout << "YOU PRESSED THE KEY!" << std::endl;
    }
    virtual void unsetKeyPressed()
    {
        keypressed = false ;
        std::cout << "YOU RELEASED THE KEY!" << std::endl;
    }
protected:
    static bool keypressed ;
private:
};

// Now an example child class
class InputHandlerChild : public InputHandlerParent {
public:
    InputHandlerChild() :
        InputHandlerParent()
    {};
protected:
private:
};

// Define keypressed
bool InputHandlerParent::keypressed = false ;

所有继承的子类共享keypressed 变量,所以如果你这样做:

#include <iostream>
int main()
{
    InputHandlerChild child1 ;
    InputHandlerChild child2 ;

    std::cout << "Child1 pressed: " << child1.isKeyPressedAndTriggerOnlyOncePls() << std::endl;
    std::cout << "Child2 pressed: " << child2.isKeyPressedAndTriggerOnlyOncePls() << std::endl;

    // Now set the key as pressed
    child1.setKeyPressed() ;

    std::cout << "Child1 pressed: " << child1.isKeyPressedAndTriggerOnlyOncePls() << std::endl;
    std::cout << "Child2 pressed: " << child2.isKeyPressedAndTriggerOnlyOncePls() << std::endl;

    // Unset the key ONLY if it was set for child2
    if (child2.isKeyPressedAndTriggerOnlyOncePls()) {
        child2.unsetKeyPressed() ;
    }

    std::cout << "Child1 pressed: " << child1.isKeyPressedAndTriggerOnlyOncePls() << std::endl;
    std::cout << "Child2 pressed: " << child2.isKeyPressedAndTriggerOnlyOncePls() << std::endl;

    return 0 ;
}

这给出了输出

Child1 pressed: 0
Child2 pressed: 0
YOU PRESSED THE KEY!
Child1 pressed: 1
Child2 pressed: 1
YOU RELEASED THE KEY!
Child1 pressed: 0
Child2 pressed: 0

所以即使我只为一个孩子按下它,每个人都知道它被按下了。基本上,无论何时按下该键,您都可以调用setKeyPressed()keypressed 设置为true。然后,每当发生取消设置键的操作时,您可以调用 unsetKeyPressed() 让所有人知道该键不再被按下。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多