如何在C++类和Lua之间共享变量?

4

我对Lua还比较新,正试图在我正在开发的游戏引擎中实现Lua脚本来控制逻辑。到目前为止,我已经成功通过引擎运行了Lua,并且能够从C调用Lua函数以及从Lua调用C函数。

现在引擎的工作方式是,每个对象类都包含一组变量,引擎可以快速地迭代这些变量以进行绘制或物理处理。虽然所有游戏对象都需要访问和操作这些变量才能使游戏引擎看到任何更改,但它们可以自由创建自己的变量,因为Lua在这方面非常灵活,所以我不会遇到任何问题。

无论如何,当前游戏引擎部分都位于C语言领域,出于性能原因,我真的希望它们能够保持在那里。因此,在理想情况下,当生成新的游戏对象时,我需要能够将这个标准的变量集作为Lua对象基类的一部分赋予Lua读写权限,然后其游戏逻辑就可以任意使用这些变量。

到目前为止,我已经保留了两个独立的对象表——Lua会生成一个新的游戏对象并将其添加到一个数字索引的全局对象表中,然后调用C++函数,该函数创建一个新的GameObject类并将Lua索引(int类型)与该类注册。这样做很好,C++函数现在可以看到Lua对象,并且可以使用dostring轻松地在Lua领域执行操作或调用函数。

现在我需要做的是将属于GameObject类的C++变量暴露给Lua,但是Google没有为我提供有用的信息。我遇到了一个非常好的方法(链接),该方法详细说明了如何使用标记进行此过程,但我读到了这种方法已被弃用,而应该使用元表。

那么,实现这一点的理想方法是什么?学习如何使用libBind或某些等效方法传递类定义是否值得麻烦,还是有简单的方法可以仅在生成时向全局Lua对象注册每个变量?截至Lua 5.1.4,最佳方法是什么?

1个回答

7

一种方法是使用:

  • 指向C++变量的轻量用户数据(lightuserdata)
  • 一个C函数来访问使用轻量用户数据指向的C++变量
  • 将轻量用户数据作为C函数的upvalue以便一个函数足以处理所有变量
  • 使用函数的参数数量来选择获取或设置变量

例如:

int game_state_var_accessor (lua_State *L)
{
    int *p = lua_topointer(L, lua_upvalueindex(1));
    if (lua_gettop(L) == 0)
    {   // stack empty, so get
        lua_pushinteger(L, *p);
        return 1;
    }
    else
    {   // arg provided, so set
        *p = lua_tointeger(L,1);
        return 0;
    }
}

当您创建一个新的游戏状态时,可以使用以下方式为每个变量创建访问器:
lua_pushlightuserdata(L, (int *)p); // where p points to your variable
lua_pushcclosure(L, game_state_var_accessor, 1);

这个访问器现在在堆栈上,可以绑定到全局名称或Lua类中方法的名称。如果您的Lua类表在索引t处,则应该是这样:

lua_setfield(L, t, "name_of_accessor");

问题:您将指针p转换为(int *),但是在文档中lua_pushlightuserdata接受(void *)。除了代码可读性之外,以这种方式强制转换是否有任何好处?我想无论如何都需要为不同类型的变量创建单独的包装器函数,这似乎有点奇怪。 - Blank
强制转换只是为了突出与game_state_var_accessor返回类型的对应关系,换句话说,是为了可读性。如果您正在为其他类型创建包装器,您可以将其重命名为game_state_int_accessor以保持清晰。 - Doug Currie
这个解决方案非常好用。非常感谢!是的,我最终使用了不同的绑定函数,因为每个都需要一个不同的处理函数。我还在学习中,但 Lua 的通信 API 真是太聪明了,我很喜欢它。^_^ - Blank
啊,这比我的解决方案干净多了。我不太习惯使用闭包,所以从来没有想过要用它们。 - Tom Savage

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接