如何将lua函数绑定到C++;功能? 我有一个叫做实体的类,它有很多功能,比如OnPoCoP、OnDROP、OnUnter等。我想做的是,编写一个脚本,定义所有这些函数,并使它们从C++函数中调用。因此,C++中定义的函数只调用具有相应功能的相应的Lua函数。
但问题是,我希望我编写的每个脚本,程序中的每个实体都在自己的范围内工作如何将lua函数绑定到C++;功能? 我有一个叫做实体的类,它有很多功能,比如OnPoCoP、OnDROP、OnUnter等。我想做的是,编写一个脚本,定义所有这些函数,并使它们从C++函数中调用。因此,C++中定义的函数只调用具有相应功能的相应的Lua函数。,c++,lua,luabind,C++,Lua,Luabind,但问题是,我希望我编写的每个脚本,程序中的每个实体都在自己的范围内工作 我正在使用LuaBind,而且我以前没有使用Lua的经验,所以我在这里有点迷茫。我不使用Lua绑定,但这可能会有所帮助。其思想是在您的C++类中登记Lua函数,并在C++类中保留对Lua函数的引用。 定义一个从C/C++调用的LUA函数,我使用LualLeReF来存储对C++对象中回调函数的引用。p> // a little helper function template <typename T> T *Lua
我正在使用LuaBind,而且我以前没有使用Lua的经验,所以我在这里有点迷茫。我不使用Lua绑定,但这可能会有所帮助。其思想是在您的C++类中登记Lua函数,并在C++类中保留对Lua函数的引用。
定义一个从C/C++调用的LUA函数,我使用LualLeReF来存储对C++对象中回调函数的引用。p>
// a little helper function
template <typename T>
T *Lua_getUserData(lua_State *L) {
assert(lua_isuserdata(L, 1) == 1);
T **v = (T **) lua_touserdata(L, 1);
assert(v != NULL);
return *v;
}
int lua_FormRegisterMethods(lua_State *L) {
Entity *f = Lua_getUserData<Entity>(L);
assert(lua_istable(L, 2) == 1); // check the next parameter is a table
lua_pushvalue(L,2); // dup the table
f->LuaTable = luaL_ref(L, LUA_REGISTRYINDEX); // keep a reference to the table
lua_getmetatable(L, 2); // get the metatable
lua_pushstring(L, "OnClick");
lua_rawget(L, -2); // get the OnClick Lua Function
f->LuaMethod = luaL_ref(L, LUA_REGISTRYINDEX); // save a reference to it
return 0;
}
现在,您可以调用此函数,并将self设置为先前保存的表。hth您可以使用调用Lua函数,例如
int callLuaFunction(lua_State* lua_state) {
return luabind::call_function<int>(lua_state, "myluafunction", param1);
}
int calllua函数(lua_状态*lua_状态){
返回luabind::call_函数(lua_状态,“myluafunction”,param1);
}
如果Lua函数返回一个int并接受1个参数
我很确定你可以制作你想要的任何数量的lua_State。只需将实体的正确代码传递到
call_function
中,就可以以您可能希望的方式完全实现这一点,这需要在Lua的一些更为深奥的部分中进行挖掘。不过,花时间是值得的。我将展示一个非常精简的版本,说明我是如何处理这个问题的。请注意,这里有很多小的部分在一起工作,主要是保存和调用保存的函数,并使用C++对象作为LUA用户数据。
首先需要一个C++类,它将事件处理程序(Lua函数)存储为简单的int的LUA引用。我在这里使用数组,但你可以使用任何有意义的东西。这里发生的主要事情是,您希望能够调用int引用所引用的lua函数
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include <string>
#include <iostream>
#include <assert.h>
using namespace std;
enum enum_event_types {
ON_USE, ON_DROP, ON_WHATEVER, EVENT_COUNT
};
class Entity {
private:
int events[EVENT_COUNT];
public:
lua_State* lua;
void setEventHandler(int event, int ref) {
assert(event < EVENT_COUNT);
events[event] = ref;
}
void callEventHandler(int event) {
int error;
assert(event < EVENT_COUNT);
// to call the function we need to get it from the registry index
lua_rawgeti(lua, LUA_REGISTRYINDEX, events[event]);
error = lua_pcall(lua, 0, 0, 0); // use protected call for errors
if (error) {
printf("error: %s", lua_tostring(lua, -1));
lua_pop(lua, 1);
}
}
};
现在设置Lua状态,创建实体表并创建测试。测试将创建一个实体,并将其事件处理程序设置为传递给它的Lua函数。最后测试了C++对象调用的Lua函数。
int main() {
Entity** e;
int error;
lua_State* L=lua_open();
luaL_openlibs(L);
luaL_register(L, "Entity", L_entityMethods);
lua_pushvalue(L,-1);
lua_setfield(L, -2, "__index");
lua_pop(L, 1);
luaL_loadstring(L,
"e = Entity.new(); "
"e:setOnUse(function()"
" print('Some of them want to use you')"
"end);");
error = lua_pcall(L, 0, 0, 0);
if (error) {
printf("error: %s", lua_tostring(L, -1));
lua_pop(L, 1); /* errors must be popped from stack */
}
lua_getglobal(L, "e");
if (lua_isuserdata(L, 1)) {
e = (Entity**) lua_touserdata(L, 1);
(*e)->callEventHandler(ON_USE);
}
return 0;
}
这还远远没有完成。首先,如果您需要设置两次事件处理程序,那么首先需要使用luaL_unref清除旧的引用。其次,您可能希望将发生的事件的一些数据传递给事件处理程序。当前事件处理程序不获取任何数据,因此api的用户几乎没有什么可继续的。它可能至少应该传递对调用事件的对象的引用。这可以用来在Lua中创建非常强大和可用的API。祝你好运 是的,当然可以,或者你可以这样做:-)-你是在建议每个实体实例都有一个单独的lua状态吗?等等,你是在问如何定义继承lua中实体的类,以便在调用onXXX虚拟方法时调用你的lua方法?如果是-这是你的链接:@sbk,我认为这是解决问题的好办法。如果我有行为不同的对象,那么将它们存储为单独的类才是正确的。谢谢您希望每个脚本都在自己的作用域中运行,还是希望每个函数都运行?您正在使用哪个版本的Lua?使用Lua5.2,设置脚本或函数的环境非常简单。这可能会使你想完成的事情变得容易。如果我不在基础上,你能提供更多的细节来说明为什么你希望每个脚本在它自己的范围内执行吗?好的,如果我想为一个对象使用一些额外的变量,我可以在派生类中定义这些变量并使用它们。因此,我为定义类的实体编写了一个脚本文件,然后在运行主脚本的全局范围内创建它的对象。因此,我在类中定义的任何变量都保留在类中,并且不会干扰主脚本文件中定义的任何变量。
int L_newEntity(lua_State* L) {
Entity **e = (Entity **)lua_newuserdata(L, sizeof(Entity *));
*e = new Entity();
(*e)->lua = L;
lua_getglobal(L, "Entity");
lua_setmetatable(L, -2);
return 1;
}
int L_setOnUse(lua_State* L) {
Entity** e = (Entity**) lua_touserdata(L, 1);
lua_pushvalue(L, 2);
int ref = luaL_ref(L, LUA_REGISTRYINDEX);
(*e)->setEventHandler(ON_USE, ref);
return 0;
}
// this will be exposed to Lua as a table called Entity
static const luaL_Reg L_entityMethods[] = {
{"new", L_newEntity},{"setOnUse", L_setOnUse},{NULL, NULL}
};
int main() {
Entity** e;
int error;
lua_State* L=lua_open();
luaL_openlibs(L);
luaL_register(L, "Entity", L_entityMethods);
lua_pushvalue(L,-1);
lua_setfield(L, -2, "__index");
lua_pop(L, 1);
luaL_loadstring(L,
"e = Entity.new(); "
"e:setOnUse(function()"
" print('Some of them want to use you')"
"end);");
error = lua_pcall(L, 0, 0, 0);
if (error) {
printf("error: %s", lua_tostring(L, -1));
lua_pop(L, 1); /* errors must be popped from stack */
}
lua_getglobal(L, "e");
if (lua_isuserdata(L, 1)) {
e = (Entity**) lua_touserdata(L, 1);
(*e)->callEventHandler(ON_USE);
}
return 0;
}