I'm trying to use Lua with my game engine prototype but I'm stuck with odd error.
My target is to create X objects in loop with Lua and render them.
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
If I do it this way, code works without errors, but game crashes in random time from instant to few secs. If I use this code with only objects created in loops, not those created manually, game crashes instantly.
However if I write Lua code equivalent in C++, it runs without any problem.
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)));
}
This is my Lua binding
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)
];
}
Every method accepts and returns void except AddChild
virtual void AddChild(Node *child);
Sprite and Box aand Circle Objects are inherited from Node class.
Does any one have an idea what can cause this odd error? I would be glad for any help.
You have serious ownership problems.
In C/C++, a piece of code "owns" a pointer or other resource if that code or object takes on the responsibility for destroying it. It keeps it alive while it needs it, and it ensures that it is destroyed when it is finished using it.
Maintaining an understanding of who owns what is vital for any even mildly complex C or C++ program.
When Luabind creates a C++ object from Lua, then the Lua script owns that object. This means that Lua's garbage collector will decide when to delete it.
So this:
Will create a
Spriteobject who's lifetime is governed by the Lua state. When the Lua state no longer has any active references to it, then the Lua state will be free to delete it.I don't know how your code works, but this line:
Suggests that
CircleObject's constructor is supposed to claim ownership over the object it is given (thus theCircleObjectdecides when to delete it). If that's true, then you need to actually state that when you bind this constructor with Luabind.If
CircleObject's constructor is not supposed to take ownership, then... well, quite frankly your design is suspect; long-term storage of a pointer that you don't own is just begging for something to get screwed up. But if it's really supposed to store a pointer that's owned by someone else, then you need to use Lua mechanisms to ensure that theSpriteremains alive so long asCircleObjectdoes.Similarly, the
Node::AddChildfunction looks like it's claiming ownership of whatever node it is given. This would be done like this:The
_1means the first parameter of the function. This means that theNodeclaims ownership of the first parameter; if it's owned by Lua, this ownership chain is now broken, and C++ now owns the object.Personally, I would say that this API is... not good for Lua. You seem to want all of the minor object ownership to be done in C++ code. So Lua should call C++ functions that set all of these minor objects up without Lua having to interfere. Lua should call a member function of a
NodeManagerin order to get/create aNode, then it should call a function that will create aSpritewithin thatNode.Lua shouldn't have to deal with the minutiae of
BoxObjectand such. It shouldn't have to directly create aSpriteobject and put it into aNode.Also, again personally, this API is not good for C++ either. If
Spriteneeds to be stored in some kind of container, and that container needs to be stored in some kind ofNode, then it should not be possible to create aSpritewithout storing it in a container. This is what factory functions are for. I'm not even sure whatBoxObjectandCircleObjectare for, sinceSpriteseems to be doing all the work.