具有私有覆盖属性的 C++ GetAsyncKeyState()

C++ GetAsyncKeyState() with private overridden attributes

我正在尝试弄清楚如何将 GetAsyncKeyState 与基于 class 的私有属性 forwardbackwards 一起使用。我需要能够将 GetAsyncKeyState 重置为其他按键。任何的想法? 也许用其他按键覆盖 forwardbackwards

#include <iostream>
#include <windows.h>
#include <string>
#include<conio.h>
using namespace std;
bool reset_defaults = false;

class Base {
protected: // OR private
    int forward = VK_UP, backwards = VK_DOWN;
public: //...
}
////////////
class Move : public Base {
public:
    Base def;
    int move() {
        while (true) {
            if (GetAsyncKeyState(forward) < 0){
                cout << ("forward >>>\n");
                if (GetAsyncKeyState(forward) == 0){
                    cout << ("Stopped\n");
                }
             }
             if (GetAsyncKeyState(VK_SPACE) < 0){break;}
         }
}
int main() {
Move move;
move.move();
}

抱歉,我想我还没有完全理解这一切的逻辑。

PS更新:

如何覆盖 baseKeys 值:

class MovementKeys {
protected:
    int baseKeys(int default_key_forward, int default_key_backward, int default_key_left, int default_key_right){
        default_key_forward = VK_UP;
        default_key_backward = VK_DOWN;
        default_key_left = VK_LEFT;
        default_key_right = VK_RIGHT;
    }
public:
    int definedCommand(int default_key_forward, int default_key_backward, int default_key_left, int default_key_right) {
        while (reset_defaults == false)
        {
            cout << ("HERE 1 \n");
            if (GetAsyncKeyState(default_key_forward) < 0)
            {
                cout << ("forward\n");
            }
            if (GetAsyncKeyState(default_key_backward) < 0)
            {
                court << ("backwards\n");
            }
            if (GetAsyncKeyState(default_key_left) < 0)
            {
                cout << ("left\n");
            }
            if (GetAsyncKeyState(default_key_right) < 0)
            {
                cout << ("right\n");
            }
            if (GetAsyncKeyState(VK_SPACE) < 0) { break; }

        }
        return 0;
    }
    int derived_newKeys(int default_key_forward, int default_key_backward, int default_key_left, int default_key_right) {
        return baseKeys(default_key_forward, default_key_backward, default_key_left, default_key_right);
    }

您可能想使用成员变量来存储键。您可以在构造函数中设置变量(默认值或更改值),而不是使用新键派生 class,并且稍后还可以更改键分配。

您可能想创建一个单独的 class,它对事件做出反应。

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

using namespace std;

class World {
    public:
        void forward() { y--; };
        void backward() { y++; };
        void left() { x--; };
        void right() { x++; };

    private:
        int x = 0;
        int y = 0;
};

class MovementKeys {
// member variables
private:
    // keep reference to world instead of copy; main() has to make sure World object outlives MovementKeys object
    World& world;

    int key_forward;
    int key_backward;
    int key_left;
    int key_right;

public:
    // constructor, which only sets world, but keeps the keys at their default settings
    //
    // world has to be initialized before the constructor function body
    // as references have no default value
    // put initialization in member initialization list

    MovementKeys(World& w) : world(w)
    {
        key_forward = VK_UP;
        key_backward = VK_DOWN;
        key_left = VK_LEFT;
        key_right = VK_RIGHT;
    }

    // constructor which modifies keys
    MovementKeys(World& w, int change_key_forward, int change_key_backward, int change_key_left, int change_key_right) : world(w)
    {
        changeKeys(change_key_forward, change_key_backward, change_key_left, change_key_right);
    }

    // command loop controlled by keys
    int definedCommand()
    {
        while (true)
        {
            cout << ("HERE 1 \n");
            if (GetAsyncKeyState(key_forward) < 0)
            {
                cout << ("forward\n");
                world.forward();
            }
            if (GetAsyncKeyState(key_backward) < 0)
            {
                cout << ("backwards\n");
                world.backward();
            }
            if (GetAsyncKeyState(key_left) < 0)
            {
                cout << ("left\n");
                world.left();
            }
            if (GetAsyncKeyState(key_right) < 0)
            {
                cout << ("right\n");
                world.right();
            }
            // optionally change keys from within while loop
            if (GetAsyncKeyState(VK_BACK) < 0)
            {
                key_forward = VK_RETURN;
            }
            if (GetAsyncKeyState(VK_SPACE) < 0)
            {
                break;
            }
        }
        return 0;
    }

    // function for changing the keys stored in the member variables
    // can be called by constructor or externally
    void changeKeys(int change_key_forward, int change_key_backward, int change_key_left, int change_key_right)
    {
        key_forward = change_key_forward;
        key_backward = change_key_backward;
        key_left = change_key_left;
        key_right = change_key_right;
    }
};

int main()
{
    World earth;

    // use default keys, declares local variable and constructs MovementKeys object called move
    MovementKeys move(earth);
    move.definedCommand();

    // use custom keys, share same world, declares local variable and constructs MovementKeys object called move2
    // static_cast<int>() with a letter in a literal char parameter works, because the VK_ values of letter keys are the actual ASCII values (on purpose by Microsoft, I would assume)
    MovementKeys move2(earth, static_cast<int>('W'), static_cast<int>('S'), static_cast<int>('A'), static_cast<int>('D'));
    move2.definedCommand();

    // change keys in move2
    move2.changeKeys(VK_LBUTTON, VK_RBUTTON, VK_CONTROL, VK_SHIFT);
    move2.definedCommand();

    // run first one again for the fun of it
    move.definedCommand();
}

或者仅传递 World&,它在 definedCommand 中使用(同时能够使用多个世界):

class World {
    // ...
};

class MovementKeys {
// member variables without world, we can also put default value here
private:
    int key_forward = VK_UP;
    int key_backward = VK_DOWN;
    int key_left = VK_LEFT;
    int key_right = VK_RIGHT;

public:
    // default constructor with no parameters, delegate to other constructor
    // delegating not necessary, as the default values are set above anyway; just demonstrating various techniques for initializing member variables
    MovementKeys() : MovementKeys(VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT) {};

    // constructor which modifies keys, put everything in member initialization list
    MovementKeys(int change_key_forward, int change_key_backward, int change_key_left, int change_key_right) : key_forward(change_key_forward), key_backward(change_key_backward), key_left(change_key_left), key_right(change_key_right) {};

    // command loop controlled by keys, pass World& here as parameter
    int definedCommand(World& world)
    {
        while (true)
        {
           // ...
        }
        return 0;
    }

    void changeKeys(int change_key_forward, int change_key_backward, int change_key_left, int change_key_right)
    {
        // ...
    }
};

int main()
{
    // use default keys, declares local variable and constructs MovementKeys object called move
    MovementKeys move;

    // use custom keys, declares local variable and constructs MovementKeys object called move2
    MovementKeys move2(static_cast<int>('W'), static_cast<int>('S'), static_cast<int>('A'), static_cast<int>('D'));

    MovementKeys defaultMenuKeys;

    World earth;
    World moon;
    World menu; // between moving in worlds, we want to control some settings in a menu

    move.definedCommand(earth);
    move2.definedCommand(earth);
    move2.definedCommand(moon);

    // change keys in move2
    move2.changeKeys(VK_LBUTTON, VK_RBUTTON, VK_CONTROL, VK_SHIFT);
    move2.definedCommand(earth);

    defaultMenuKeys.definedCommand(menu);

    // run first one again for the fun of it
    move.definedCommand(moon);
}

你可以引入一个 (class) enum 和状态列表,为什么 definedCommand() returns:

// outside or can be put into MovementKeys and henceforth used as MovementKeys::ReturnReason
class enum ReturnReason { EXIT, NEWKEYS, SHOWMENU, SWITCHWORLD };

// in class MovementKeys
ReturnReason definedCommand() {
    // ...
    return NEWKEYS;
    // ...
    return EXIT;
    // ...
    return SHOWMENU;
    // ...
}

// in main()
ReturnReason r = definedCommand();
if (r == NEWKEYS)
    move2.changeKeys(...);
else if (r == EXIT)
    return 0;

如果您还使用 'trick' 来控制菜单,现在对 World 使用虚拟继承可能是有意义的。由于 normal World 和菜单 World 的反应可能完全不同。 (基础 class(祖先)将是 World,它被 MovementKeys 识别。您的实际 World 是派生(子)classes 的对象,具有更具体的行为。

然后可以调用

definedCommand 并且 运行 与基数 class World.

的任何派生 class