Lua嵌入C++中是否能够拥有持久局部变量?如果不能,那么有哪些脚本语言可以实现这点?

使用 LuaBind 将 Lua 嵌入我的 C++ 应用程序。我需要有跨越多个运行时的变量,不能被运行相同文件名的其他对象访问。

例如:假设我有一个名为 NPC 的类。一个 NPC 拥有一个字符串,即它运行的脚本的名称。当创建 NPC 时,会创建一个名为 Health 的变量。当 NPC 被击中时,它们会失去 5 点生命值。脚本应该像这样在 Lua 中:

local health = 10

function onHit()
    health = health - 5
end

我所拥有的问题是运行这个脚本的每个 NPC 都没有自己的健康实例。例如,假设我创建 NPC A,并从其健康状况中减去 5 点。然后,我创建 NPC B。因为它将健康值重置为 10,所以如果我告诉 NPC A 打印健康值,它将给我返回 10,尽管它应该是 5。

如果我为每个对象拥有一个不同的 Lua 实例,那么它将按照这种方式工作,但我会同时拥有数百个实例,我理解这不是一个好事情。

是否有办法使变量在 Lua 中像这样工作?如果没有,是否有一种脚本语言能够以有效的方式工作?

以下是我正在测试的代码:

Lua:

local health = 10;

function onHit()
    health = health - 5
    print_out(health)
end

C++:

class NPC
{
public:
   NPC(lua_State* inState);
   void onHit();

   const char* behavior;
   lua_State* luaState;
};

NPC::NPC(lua_State* inState)
{
   luaState = inState;
   behavior = "testBehavior.lua";
   luaL_dofile(luaState, behavior);
}

void NPC::onHit()
{
   luaL_loadfile(luaState, behavior);
   luabind::call_function<int>(luaState, "onHit");
}

void print_out(int number) {
   cout << "Health : " << number << endl;
}

int main()
{
   lua_State *myLuaState = luaL_newstate();
   luabind::open(myLuaState);

   luabind::module(myLuaState) [
      luabind::def("print_out", print_out)
   ];

   NPC test(myLuaState);
   NPC test2(myLuaState);
   test.onHit();
   test2.onHit();
   test.onHit();

   lua_close(myLuaState);
}
点赞
用户1680957
用户1680957

我不了解 Lua,所以我不能谈论那个。这个问题也标记了 Python。对于 Python,我认为你可以序列化所有重要的本地变量。

另外,您可以查看我的技巧,在此处持久化称为 PyDON 的字典:http://code.activestate.com/recipes/577508-pydon-an-alternative-to-xml/

还要检查这个,我认为这将更有帮助:如何将 Python 字典序列化为字符串,然后再转回字典?

2012-12-30 03:57:43
用户88888888
用户88888888

可能看起来有点过头,但为什么不将所需的值存储在 SQLite 表中呢?

2012-12-30 04:00:34
用户1031671
用户1031671

你可以去了解一下 Lua 的 闭包。它看起来像这样:

function healthPoints()
    local health = 10
    return function()
        health = health - 5
        return health
    end
end

这样每个 NPC 都有自己的函数和计数器。每次他们被攻击时,只需调用 onHit 函数。使用方法如下:

npc1.onHit = healthPoints()
npc2.onHit = healthPoints()
npc1.onHit() -- 现在为 5,而 npc2 仍为 10

你可以像这样添加参数:

function healthPoints(hp)
    local health = hp
    return function(dmg)
        health = health - dmg
        return health
    end
end

npc1.onHit = healthPoints(100)
npc1.onHit(-12)

我认为这值得一试。

2012-12-30 05:05:26
用户734069
用户734069

参考一下,这是我正在测试的代码:

这里有很多问题。你不断地重新运行你的 Lua 脚本;这就是为什么它一直被重置的原因。另一个问题是,你的脚本正在创建一个全局函数,因此每次运行它时,你都会得到一个新的全局函数,它使用一个新的 local 变量。

停止使用全局变量。每个 NPC 都是一个独立的对象。因此,它需要有对象特定的数据。

behavior = "testBehavior.lua";
luaL_dofile(luaState, behavior);

这不会创建任何对象特定的数据。它只是运行一个 Lua 脚本,并完全放弃任何返回值。除非该脚本实际上将某些对象特定的内容全局存储,否则不会创建任何对象特定的数据。

你的 Lua 脚本需要返回一个包含对象特定数据的表格,该脚本需要这些数据来处理对象。脚本应该像这样:

local function onHit(self)
    self.health = self.health - 5
end

return {
  health = 10,
  onHit = onHit,
}

你的 C++ 代码需要在 NPC 类中 存储 这个表格,然后使用它。这可以通过 Luabind 调用轻松完成。你的构造函数应该像这样:

NPC::NPC(lua_State* L)
{
    behavior = "testBehavior.lua";
    int err = luaL_loadfile(L, behavior);
    //处理编译器错误。千万不要忘记这个!
    luabind::object func = luabind::from_stack(L, -1);
    lua_pop(L, 1);
    luaData = func(); //为运行时错误捕获异常
    lua_pop(L, 1);
}

在你的类中,不要有 lua_State* luaState,而要保留一个 luabind::object luaData。如果需要 lua_State,则可以从 luabind::object 中获取一个。

要调用你的 Lua onHit 函数,只需使用 luabind::object 接口:

void NPC::onHit()
{
    luaData["onHit"](luaData);
}

请注意,你 不需要 重新运行 Lua 脚本。这就是你的问题所在。你只需调用 Lua 脚本已经定义的函数。

现在,你似乎希望使用局部变量而不是表格内存。这很好;这将防止 C++ 代码直接访问 health(除非使用技巧)。这会简化我们的代码,因为我们不必将 luaData 传递给 onHit。你可以在 Lua 中这样做:

local health = 10
local NPC = {}

function NPC.onHit()
  health = health - 5
end

return NPC

NPC 构造函数不需要更改;只需要更改我们调用 onHit

void NPC::onHit()
{
    luaData["onHit"]();
}

如果你坚决要使用全局变量,你可以操纵环境,但这相当复杂。它将提供确保个别脚本调用之间的隔离。

2012-12-30 21:30:41