我已经使用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)
endC++:
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);
}发布于 2012-12-30 11:57:44
我不知道Lua的事,所以我不会说的。这个问题也被标记为python。为此,我认为你可以序列化所有“重要”的局部变量。
或者,您可以尝试一下我的技巧,在这里持久化一个名为PyDON的字典:http://code.activestate.com/recipes/577508-pydon-an-alternative-to-xml/
另外检查一下,我认为这会更有帮助:How do I serialize a Python dictionary into a string, and then back to a dictionary?
发布于 2012-12-30 13:05:27
你可以查一下Lua的closures。它看起来像这样:
function healthPoints()
local health = 10
return function()
health = health - 5
return health
end
end发生的情况是,每个NPC都有自己的函数和计数器。每次命中它们时,您只需调用onHit函数。你可以这样使用它:
npc1.onHit = healthPoints()
npc2.onHit = healthPoints()
npc1.onHit() -- Now at 5, while npc2 is still at 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-31 05:30:42
作为参考,下面是我正在测试的代码:
这里有很多错误之处。您不断地重新运行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);
//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);
}您可以在类中保留一个luabind::object luaData,而不是让lua_State* luaState出现在您的类中。如果你需要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 NPCNPC构造函数不需要更改;只需调用onHit即可。
void NPC::onHit()
{
luaData["onHit"]();
}如果你一心想使用全局变量,你可以在环境中玩游戏,但那是相当复杂的。它将在各个脚本调用之间提供有保证的隔离。
https://stackoverflow.com/questions/14087686
复制相似问题