我正在尝试将Lua用于我的游戏引擎原型,但我遇到了奇怪的错误。
我的目标是使用Lua在循环中创建X对象并渲染它们。
sprite = Sprite("icon.jpg", 300, 300, 0)
sprite2 = Sprite("icon.jpg", 100, 100, 0)
b1 = BoxObject(sprite)
b2 = BoxObject(sprite2)
sprite3 = Sprite("circle.png", 200, 100, 0)
sprite4 = Sprite("circle.png", 300, 100, 0)
b3 = CircleObject(sprite3)
b4 = CircleObject(sprite4)
n = Node()
n:AddChild(b1)
n:AddChild(b2)
n:AddChild(b3)
n:AddChild(b4)
for i = 0, 10, 1 do
x = math.random(700)
y = math.random(500)
n:AddChild(BoxObject(Sprite("icon.jpg", x, y, 0)))
end
for i = 0, 10, 1 do
x = math.random(700)
y = math.random(500)
local s = Sprite("circle.png", x, y, 0)
local o = CircleObject(s)
n:AddChild(BoxObject)
end
如果我这样做,代码可以正常运行,但游戏会在瞬间到几秒的随机时间内崩溃。如果我只使用在循环中创建的对象,而不是手动创建的对象,则游戏会立即崩溃。
但是,如果我在C ++中编写等效的Lua代码,它运行没有任何问题。
for(int i = 0; i < 20; i++){
float x = rand() % 700;
float y = rand() % 500;
n->AddChild(new BoxObject(new Sprite("icon.jpg", x, y)));
}
for(int i = 0; i < 20; i++){
float x = rand() % 700;
float y = rand() % 500;
n->AddChild(new CircleObject(new Sprite("circle.png", x, y)));
}
这是我的Lua绑定
static void Lua(lua_State *lua){
luabind::module(lua)
[
luabind::class_<Node>("Node")
.def(luabind::constructor<>())
.def(luabind::constructor<float, float, float>())
.def("Render", &Node::Render)
.def("Move", &Node::Move)
.def("Rotate", &Node::Rotate)
.def("AddChild", &Node::AddChild)
.def("RotateAroundPoint", &Node::RotateAroundPoint)
];
}
除AddChild
外,每个方法都接受并返回voidvirtual void AddChild(Node *child);
Sprite和Box aand Circle Objects继承自Node类。
有没有人知道什么会导致这个奇怪的错误?我会很高兴得到任何帮助。
答案 0 :(得分:1)
您有严重的所有权问题。
在C / C ++中,如果该代码或对象承担销毁它的责任,则一段代码“拥有”指针或其他资源。它在需要时保持活着,并确保在 it 使用它时它被销毁。
了解谁拥有对于任何复杂的C或C ++程序至关重要的内容。
当Luabind从Lua 创建C ++对象时,Lua脚本拥有该对象。这意味着Lua的垃圾收集器将决定何时删除它。
所以这个:
local s = Sprite("circle.png", x, y, 0)
将创建一个Sprite
对象,其生命周期由Lua状态控制。当Lua状态不再有任何活动引用时,Lua状态将可以自由删除它。
我不知道您的代码是如何工作的,但是这一行:
local o = CircleObject(s)
建议CircleObject
的构造函数声明对其给定的对象声明所有权(因此CircleObject
决定何时删除它)。如果这是真的,那么当你用Luabind绑定这个构造函数时,你需要实际说明。
如果CircleObject
的构造函数不应该取得所有权,那么......坦率地说,你的设计是可疑的;长期存储一个你不拥有的指针只是在乞求搞砸了。但是如果真的应该存储一个由其他人拥有的指针,那么你需要使用Lua机制来确保Sprite
只要CircleObject
能够保持活着。
同样,Node::AddChild
函数看起来声称它所拥有的任何节点的所有权。这将是这样做的:
.def("AddChild", &Node::AddChild, adopt(_1))
_1
表示函数的第一个参数。这意味着Node
声明了第一个参数的所有权;如果它由Lua拥有,那么这个所有权链现在已被破坏,C ++现在拥有该对象。
就个人而言,我会说这个API对Lua来说并不好。您似乎希望所有次要对象所有权都在C ++代码中完成。所以Lua应该调用C ++函数来设置所有这些小对象,而Lua不必干涉。 Lua应该调用NodeManager
的成员函数来获取/创建Node
,然后它应该调用一个在Sprite
内创建Node
的函数。 / p>
Lua不应该处理BoxObject
这样的细枝末节。它不应该直接创建Sprite
对象并将其放入Node
。
此外,个人而言,此API也不适合 C ++ 。如果Sprite
需要存储在某种容器中,并且该容器需要存储在某种Node
中,那么就不可能创建Sprite
没有将其存储在容器中。这就是工厂的功能。我甚至不确定BoxObject
和CircleObject
的用途,因为Sprite
似乎正在完成所有工作。