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)
你可以看看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)
我认为这值得一试.
作为参考,这是我正在测试的代码:
这里有很多错误。你不断地重新运行你的 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(并非没有欺骗)。它会简化我们的代码,因为我们不必传递luaData到onHit. 你可以在 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)
如果您执意要使用全局变量,您可以与环境一起玩游戏,但这相当复杂。它将在各个脚本调用之间提供有保证的隔离。