作者:loloyoyo555 | 来源:互联网 | 2023-05-19 17:36
Imwritingasimple,lightweightengineinD.FortheinputcallsIuseGLFW3.Thelibraryinquest
I'm writing a simple, lightweight engine in D. For the input calls I use GLFW3. The library in question uses callbacks to send input events to the program.
我在d中编写了一个简单的轻量级引擎,用于输入调用GLFW3。该库使用回调函数将输入事件发送到程序。
What I would like is to use a method from a class as the callback function, rather than a function. This is proving difficult (just as it is in C++). I believe there is an elegant way to do it, but this is how I got it right now.
我想要的是使用一个类的方法作为回调函数,而不是函数。事实证明这是困难的(就像在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);
}
Here is the definition of the callback setting function and type:
下面是回调设置函数和类型的定义:
extern (C) {
alias GLFWkeyfun = void function(GLFWwindow*, int, int, int, int);
GLFWkeyfun glfwSetKeyCallback(GLFWwindow*, GLFWkeyfun);
}
What I would like to do instead, is create a method that is part of the class. Is there any way to do this?
我想要做的是创建一个方法,它是类的一部分。有什么办法吗?
A solution I tried was a static
method wrapped around in extern (C)
, this worked for calling it, but then I could (obviously) not access this
or any other methods, which defeats the point of the exercise.
我尝试过的一个解决方案是在外部(C)中封装的静态方法,这个方法可以调用它,但是我可以(很明显)不能访问这个或任何其他方法,这就违背了这个练习的要点。
Thanks in advance.
提前谢谢。
2 个解决方案
0
The way I'd do it is to have a static map of the pointers to the class, so like:
我这样做的方法是有一个指向类的指针的静态映射,比如:
static YourWindowClass[GLFWwindow*] mappings;
Then, in the constructor, once you get a GLFWwindow pointer, add it right in:
然后,在构造函数中,一旦获得了一个GLFWwindow指针,就将它添加到:
mappings[m_Window.window] = this;
Now, make the static extern(C) function to use as the callback. When it gets a pointer from C, look up your class reference in that mappings array and then go ahead and call the member function through that, forwarding the arguments.
现在,让静态外部(C)函数用作回调函数。当它从C获取一个指针时,在那个映射数组中查找你的类引用,然后通过它调用成员函数,转发参数。
So a bit of an extra step, but since it doesn't look like the callback lets you pass user-defined data to it (BTW, attention all lib writers: user-defined void* to the callbacks is sooooo useful, you should do it whenever possible!), but since it doesn't do that the associative array is the next best thing.
所以一个额外的步骤,但是因为它看起来不像它的回调函数可以通过用户定义的数据(顺便说一句,所有自由作家注意:用户定义的回调函数void *是如此的有用,你应该尽可能地做到!),但由于没有关联数组是再好不过的事情了。
0
Well, I have figured it out my own. The solution I went with was a Singleton class InputManager
. Instances of RenderWindow
attach themselves to it with the following function. The InputManager
then creates an anonymous function()
for the RenderWindow
that receives events, which then calls a function that handles the actual event.
嗯,我自己也算出来了。我使用的解决方案是一个独立类InputManager。RenderWindow的实例与下面的函数连接在一起。然后InputManager为接收事件的RenderWindow创建一个匿名函数(),然后调用一个处理实际事件的函数。
The idea is then that listeners attach themselves to the InputManager
and receive keyboard events for the RenderWindow
they requested.
然后,侦听器将自己连接到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
}
}
Works like a charm, now to figure out how to properly attach listeners elegantly.
像符咒一样工作,现在想办法正确地连接听众。
For those curious, the full source code with how this is set up can be found at https://github.com/Adel92/Mage2D. I hope it helps someone else in a similar position with callbacks.
对于那些好奇的人,可以在https://github.com/Adel92/Mage2D中找到完整的源代码。我希望它能帮助其他人在类似的岗位上有回调。