【问题标题】:How do I do a proper input class in GLFW for a game engine如何在 GLFW 中为游戏引擎做一个正确的输入类
【发布时间】:2019-08-29 14:12:02
【问题描述】:

我正在做我的一个小项目,我基本上是在创建我自己的 c++ 游戏引擎/框架来创建图形和/或简单的游戏。我将 OpenGL 与 GLFW 一起使用。我的目标是拥有类似于各种图形框架的东西,例如 raylib 或 openFrameworks(但当然被剥离了)

实际上到目前为止一切正常,但我不知道如何正确地将输入与窗口类分开,因为窗口句柄输入对我来说似乎相当笨拙,只会使窗口类变得混乱。

这是对我的窗口类的快速过度简化的重新创建。 (我没有在键码中包含枚举类。)

#pragma once
#include "../extern/GLFW/glfw3.h"
#include <string>
class Window {
private:
    GLFWwindow* mWindow;
    int mWidth;
    int mHeight;
    std::string mTitle;

public:
    Window();
    ~Window();

    void createWindow(std::string title, int width, int height);
    void mainLoop();

    GLFWwindow* getWindow() const { return mWindow; }


// Input
private:

    bool Window::getKeyStatus(KEY key) {
    static void keyCallback(GLFWwindow* mWindow, int key, int scancode, int action, int mods);
    bool isKeyDown(KEY key);
};

这是实现加

#include "Window.h"
#include <iostream>

Window::Window() {}
Window::~Window() {}

void Window::createWindow(std::string title, int width, int height) {
    if (!glfwInit());
    mWindow = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr);

    if (!getWindow()) {
        glfwTerminate();
    }


    glfwSetWindowUserPointer(getWindow(), this);
    glfwMakeContextCurrent(getWindow());


    glfwSetKeyCallback(mWindow, keyCallback);
}

void Window::mainLoop() {
    while (!glfwWindowShouldClose(getWindow())) {
        /* Render here */
        glClear(GL_COLOR_BUFFER_BIT);

        /* Swap front and back buffers */
        glfwSwapBuffers(getWindow());

        /* Poll for and process events */
        glfwPollEvents();


        if (isKeyDown(KEY::A)) {
            std::cout << "A down" << std::endl;
        }
        if (isKeyDown(KEY::B)) {
            std::cout << "B down" << std::endl;
        }

    }

    glfwTerminate();
}

void Window::keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
    Window* win = (Window*)glfwGetWindowUserPointer(window);

    if (key == (int)KEY::ESCAPE && action == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, GL_TRUE);
    } else {
        win->currentKeyState[key] = action;
    }
}

bool Window::getKeyStatus(KEY key) {
    return glfwGetKey(mWindow, (int)key);
}
bool Window::isKeyDown(KEY key) {
    bool down = false;
    if (getKeyStatus(key) == 1) {
        down = true;
    }
    return down;
}

我该如何着手呢?我的主要问题是我似乎无法连接我的窗口和输入类。我应该使用继承类还是朋友类。我应该在窗口类(我假设)中有glfw的回调还是应该将它们移动到输入类?如何连接这两个类,这样我就不必总是使用窗口指针,例如“isKeyDown(GLFWwindow* window, Key keycode)”,而是只使用“isKeyDown(Key keycode)”。如果不是太多,有人可以写一个简单的输入类吗?

提前致谢

【问题讨论】:

    标签: c++ opengl input game-engine glfw


    【解决方案1】:

    需要指出的一点是,GLFW 提供了轮询和基于回调的输入处理。在您的示例中,您同时使用:轮询处理 AB 键和回调处理 escape 键。我相信在创建单独的输入类(键盘和鼠标)时,您会发现回调更容易使用。

    使用 GLFW 的回调方法创建 KeyInput 类的方法有很多。这是我的首选技术(为适合您的代码而编写)。它允许 多个 KeyInput 实例(与单例不同),这意味着您可以为 UI 键提供一个 KeyInput 实例,一个用于 in - 游戏钥匙等。

    总而言之:每个 KeyInput 实例都会监视用户在构造时定义的按键列表的按下状态。它有一个 getter 和一个 setter 来访问任何键的按下状态(尽管 getter 和 setter 仅适用于受监控的键)。每当调用 GLFW 键输入回调(静态)时,它都会为 KeyInput所有实例 调用该设置器。实例存储在静态向量中,该向量在构造时添加并在销毁时移除。

    Input.h

    #include "../extern/GLFW/glfw3.h"
    #include <map>
    #include <vector>
    
    class KeyInput {
      // Main KeyInput functionality
      public:
        // Takes a list of which keys to keep state for
        KeyInput(std::vector<int> keysToMonitor);
        ~KeyInput();
        // If this KeyInput is enabled and the given key is monitored,
        // returns pressed state.  Else returns false.
        bool getIsKeyDown(int key);
        // See _isEnabled for details
        bool getIsEnabled() { return _isEnabled; }
        void setIsEnabled(bool value) { _isEnabled = value; }
      private:
        // Used internally to update key states.  Called by the GLFW callback.
        void setIsKeyDown(int key, bool isDown);
        // Map from monitored keyes to their pressed states
        std::map<int, bool> _keys;
        // If disabled, KeyInput.getIsKeyDown always returns false
        bool _isEnabled;
    
      // Workaround for C++ class using a c-style-callback
      public:
        // Must be called before any KeyInput instances will work
        static void setupKeyInputs(Window& window);
      private:
        // The GLFW callback for key events.  Sends events to all KeyInput instances
        static void callback(
          GLFWwindow* window, int key, int scancode, int action, int mods);
        // Keep a list of all KeyInput instances and notify them all of key events
        static std::vector<KeyInput*> _instances;
    };
    

    Input.cpp

    #include "KeyInput.h"
    #include <algorithm>
    
    std::vector<KeyInput*> KeyInput::_instances;
    
    KeyInput::KeyInput(std::vector<int> keysToMonitor) : _isEnabled(true) {
      for (int key : keysToMonitor) {
        _keys[key] = false;
      }
      // Add this instance to the list of instances
      KeyInput::_instances.push_back(this);
    }
    
    KeyInput::~KeyInput() {
      // Remove this instance from the list of instances
      _instances.erase(std::remove(_instances.begin(), _instances.end(), this), _instances.end());
    }
    
    bool KeyInput::getIsKeyDown(int key) {
      bool result = false;
      if (_isEnabled) {
        std::map<int,bool>::iterator it = _keys.find(key);
        if (it != _keys.end()) {
          result = _keys[key];
        }
      }
      return result;
    }
    
    void KeyInput::setIsKeyDown(int key, bool isDown) {
      std::map<int,bool>::iterator it = _keys.find(key);
      if (it != _keys.end()) {
        _keys[key] = isDown;
      }
    }
    
    void KeyInput::setupKeyInputs(Window& window) {
      glfwSetKeyCallback(window.getWindow(), KeyInput::callback);
    }
    
    void KeyInput::callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
      // Send key event to all KeyInput instances
      for (KeyInput* keyInput : _instances) {
        keyInput->setIsKeyDown(key, action != GLFW_RELEASE);
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2013-01-21
      • 2013-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多