Lua嵌入在C++中是否能够拥有持久的局部变量?如果没有,是否有脚本语言呢?

use*_*871 2 python scripting lua v8 luabind

我使用LuaBind在我的C++应用程序中嵌入了Lua.我需要有多个运行的变量,这些变量不能被运行相同文件名的其他对象访问.

例如:假设我有一个叫做的课程NPC.一个NPC拥有一个字符串,也就是它们运行的脚本的名称.NPC创建a 时,会创建一个名为的变量Health.当NPC被击中时,他们会失去5点健康.这些脚本在Lua中会是这样的:

local health = 10

function onHit()
    health = health - 5
end
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是每个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
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

Net*_*led 8

你可以看看Lua的闭包.它看起来像这样:

function healthPoints()
    local health = 10
    return function()
        health = health - 5
        return health
    end
end
Run Code Online (Sandbox Code Playgroud)

会发生什么是每个NPC用自己的计数器获得自己的功能.每次击中它们,您只需调用该onHit功能.你会这样使用它:

npc1.onHit = healthPoints()
npc2.onHit = healthPoints()
npc1.onHit() -- Now at 5, while npc2 is still at 10
Run Code Online (Sandbox Code Playgroud)

你会添加如下参数:

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

npc1.onHit = healthPoints(100)
npc1.onHit(-12)
Run Code Online (Sandbox Code Playgroud)

我认为这值得一试.


Nic*_*las 5

作为参考,这是我正在测试的代码:

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

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

behavior = "testBehavior.lua";
luaL_dofile(luaState, behavior);
Run Code Online (Sandbox Code Playgroud)

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

您的 Lua 脚本需要做的是返回一个表,其中包含脚本所需的对象特定数据。该脚本应如下所示:

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

return {
  health = 10,
  onHit = onHit,
}
Run Code Online (Sandbox Code Playgroud)

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

behavior = "testBehavior.lua";
luaL_dofile(luaState, behavior);
Run Code Online (Sandbox Code Playgroud)

你不是lua_State* luaState在你的班级里有,而是在你的班级里保留着luabind::object luaData。如果您需要lua_State,您可以随时从 获取luabind::object

要调用 LuaonHit函数,只需使用以下luabind::object接口:

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

return {
  health = 10,
  onHit = onHit,
}
Run Code Online (Sandbox Code Playgroud)

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

现在,您似乎想使用局部变量而不是表内存。没关系; 它会阻止 C++ 代码直接访问health(并非没有欺骗)。它会简化我们的代码,因为我们不必传递luaDataonHit. 你可以在 Lua 中这样做:

local health = 10
local NPC = {}

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

return NPC
Run Code Online (Sandbox Code Playgroud)

NPC构造器不需要改变;只是我们的电话onHit

NPC::NPC(lua_State* L)
{
    behavior = "testBehavior.lua";
    int err = luaL_loadfile(L, behavior);
    //Handle compiler errors. DON'T FORGET THIS!
    luabind::object func = luabind::from_stack(L, -1);
    lua_pop(L, 1);
    luaData = func(); //Catch exceptions for runtime errors
    lua_pop(L, 1);
}
Run Code Online (Sandbox Code Playgroud)

如果您执意要使用全局变量,您可以与环境一起玩游戏,但这相当复杂。它将在各个脚本调用之间提供有保证的隔离。