我在D中编写一个简单的轻量级引擎。对于输入调用,我使用GLFW3。有问题的库使用回调将输入事件发送到程序。
我想要的是使用类中的方法作为回调函数,而不是函数。事实证明这很困难(就像在C ++中一样)。我相信有一种优雅的方式可以做到这一点,但这就是我现在的方式。
public void initialise(string logPath) {
[...]
m_Window = new RenderWindow();
m_Window.create();
// Lets set up the input loop.
GLFWkeyfun keyCB = function(GLFWwindow* win, int key, int scancode, int action, int mods) {
printf("Got key event: %d:%d:%d:%d\n");
RenderWindow rw = Root().getRenderWindow();
switch (key) {
case KeyboardKeyID.Q:
glfwSetWindowShouldClose(win, true);
break;
case KeyboardKeyID.H:
if (rw.hidden) {
rw.show();
} else {
rw.hide();
}
break;
default:
break;
}
};
glfwSetKeyCallback(m_Window.window, keyCB);
}
以下是回调设置功能的定义和类型:
extern (C) {
alias GLFWkeyfun = void function(GLFWwindow*, int, int, int, int);
GLFWkeyfun glfwSetKeyCallback(GLFWwindow*, GLFWkeyfun);
}
我想要做的是创建一个属于类的方法。有没有办法做到这一点?
我尝试的解决方案是在static
中包含的extern (C)
方法,这可用于调用它,但后来我可以(显然)无法访问this
或任何其他方法,否定了演习的重点。
提前致谢。
答案 0 :(得分:0)
我这样做的方法是拥有一个指向类的指针的静态映射,如:
static YourWindowClass[GLFWwindow*] mappings;
然后,在构造函数中,一旦获得GLFWwindow指针,将其添加到:
mappings[m_Window.window] = this;
现在,将静态extern(C)函数用作回调。当它从C获取指针时,在该映射数组中查找您的类引用,然后继续并通过它调用成员函数,转发参数。
这是一个额外的步骤,但是因为它看起来不像回调允许你将用户定义的数据传递给它(BTW,注意所有的lib编写者:用户定义的void *到回调是sooooo有用的,你应该尽可能地做!),但是因为它没有做到这一点,关联数组是下一个最好的事情。
答案 1 :(得分:0)
好吧,我已经把它弄清楚了。我使用的解决方案是Singleton类InputManager
。 RenderWindow
的实例使用以下函数附加到它上面。 InputManager
然后为接收事件的function()
创建匿名RenderWindow
,然后调用处理实际事件的函数。
接下来的想法是,听众将自己附加到InputManager
并接收他们请求的RenderWindow
的键盘事件。
class InputManager {
private static InputManager m_Instance;
private RenderWindow[] m_Watched;
private KeyboardListener[][RenderWindow] m_KeyListeners;
public void recvKeyEvent(GLFWwindow* w, int k, int c, int a, int m) {
writeln("Received key: ", k);
}
public void watch(RenderWindow win) {
if (!isWatched(win)) {
// Relay the key callbacks onto the InputManager.
GLFWkeyfun keyCB = function(GLFWwindow* w, int k, int c, int a, int m) {
InputManager().recvKeyEvent(w, k, c, a, m);
};
glfwSetKeyCallback(win.window, keyCB);
}
}
private bool isWatched(RenderWindow win) {
foreach(RenderWindow w; m_Watched) {
if (win == w) {
return true;
}
}
return false;
}
public static InputManager opCall() {
if (m_Instance is null) {
m_Instance = new InputManager();
}
return m_Instance;
}
private this() {
// nothing
}
}
像魅力一样工作,现在要弄清楚如何正确地正确地附上听众。
对于那些好奇的人,可以在https://github.com/Adel92/Mage2D找到完整的源代码及其设置方法。我希望它可以帮助处于类似位置的其他人进行回调。