1

我正在尝试将 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 外,每个方法都接受并返回 void

virtual void AddChild(Node *child);

Sprite 和 Box a 和 Circle 对象都继承自 Node 类。

有谁知道什么会导致这个奇怪的错误?我会很高兴有任何帮助。

4

1 回答 1

1

你有严重的所有权问题。

在 C/C++ 中,如果该代码或对象负责销毁它,则一段代码“拥有”一个指针或其他资源。它在需要它时保持它的活力,并确保在用完它时将其销毁。

保持了解谁拥有对任何即使是稍微复杂的 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 应该调用 a 的成员函数NodeManager以获取/创建 a ,然后它应该调用将在 thatNode中创建 a 的函数。SpriteNode

Lua 不应该处理BoxObject诸如此类的细枝末节。它不应该直接创建一个Sprite对象并将其放入Node.

另外,就个人而言,这个 API 也不适用于C++。如果Sprite需要存储在某种容器中,并且该容器需要存储在某种容器中Node,那么如果不将其存储在容器中,就不可能创建Sprite a。这就是工厂函数的用途。我什至不确定什么BoxObjectCircleObject是为了什么,因为Sprite似乎正在做所有的工作。

于 2012-08-04T22:14:33.677 回答