Accessing std::vector elements in lua

Started by
7 comments, last by NSDuo 14 years, 2 months ago
Using lua and luabind has been very difficult, yet the results I've gotten have made it worthwhile. I have managed to get everything to compile without errors or warnings. I also managed to bind my classes, their functions, and their variables to Lua. I even got some variables bound to lua to sync with my variables in C++. In fact there is one thing left that I need to get working before I can apply everything to all my other classes. I need to access an std::vector where I store my assets. I made these two classes to manage game entities:

class entity: public sprite, public mesh, public grid
{
private:
	
	std::string name;
	
	bool render;
	
	// 0 for sprite, 1 for 3D mesh
	int type;
	
	// xyz location in space. Z will not be used in 2D games.
	float x, y, z;
	
	// xyz rotation. x and y will not be used in 2D games.
	float rotx, roty, rotz;
	
public:
	
	entity();
	
	
	// lua communication functions
	void setName(std::string name);
	std::string getName();
	
	void setRender(int r);
	int getRender();
	
	void setType(int t);
	int getType();
	
	void setLocX(float Lx);
	void setLocY(float Ly);
	void setLocZ(float Lz);
	
	float getLocX();
	float getLocY();
	float getLocZ();
	
	void setVelX(float v);
	void setVelY(float v);
	void setVelZ(float v);
	
	
	void draw();
	
};

class entityControl
{
	int noOfEntities;
	
public:
	
	std::vector<entity> entityData;
	
	entityControl();
	
	void newEntity();
	
	// lua get private vars
	int getNoOfEntities();
	
	
	
};


This is the function I use to add a new entity into the array:

void entityControl::newEntity()
{
	
	entity x;
	
	//entityData.insert(it, x);
	entityData.push_back(x);
	
	noOfEntities++;
}

My binding code (I'm only showing whats being bound):

class_<entity>("entity")
	 .def(constructor<>())
	 .property("render", &entity::getRender, &entity::setRender)
	 .property("type", &entity::getType, &entity::setType)
	 .property("x", &entity::getLocX, &entity::setLocX)
	 .property("y", &entity::getLocY, &entity::setLocY)
	 .property("z", &entity::getLocZ, &entity::setLocZ)
	 .def("setVelX", &entity::setVelX)
	 .def("setVelY", &entity::setVelY)
	 .def("setVelZ", &entity::setVelZ),
	 
	 class_<entityControl>("entityControl")
	 .def_readwrite("entityData", &entityControl::entityData, return_stl_iterator)
	 .property("noOfEntities", &entityControl::getNoOfEntities)
	 .def("newEntity", &entityControl::newEntity)

My lua script:


print(entityManager.noOfEntities)
-- accessing this variable gives me no problem. It prints 0 like it should


entityManager.newEntity()
-- this hangs the program. I got it to work once, but...

entityData[1].setType(0)
-- if the above command worked then this would crash the program


And finally the resulting run-time error: terminate called after throwing an instance of 'luabind::error' what(): lua runtime error Program received signal: “SIGABRT”. So now I'm thinking that I'm taking the wrong approach to accessing the elements of the vector. And even if I could properly bind and access a vector with lua, I would still need to get every value I changed back into C++. If I could do this, then I could apply it to all my other classes and complete the basics of my game engine. However, as I've been writing this post I feel that if I could get this working, I should make it easier for other people using luabind and the good people on these forums by making a video walk-through explaining how to set up and use lua and luabind. This way less luabind questions might be asked on this forum. So how do I access an std::vector from lua, and send it back to C++?

Macbook Pro 2.66Ghz dual core, 4GB ram, 512MB vram, MacOSX 9.1, Windows 8.1
Xcode 5.0.2, C++, lua

Advertisement
Are you checking the actual error generated by Lua when the exception is thrown? If not, it seems that might offer a clue as to what's going wrong.

Also, should this:
entityManager.newEntity()
Perhaps be:
entityManager:newEntity()
?

I realize this doesn't address your question about std::vector, but maybe it'll help get you a little closer to solving the problem.
Thank you, yes that does help. Now my script looks like this:

entityManager:newEntity()print(entityManager.noOfEntities)-- prints 1 because I successfully added an entityship = entityManager.entityData[0]-- this crashes the program... -- maybe if I accessed it like a class function and referenced the first element as 1 (I read in a lua tutorial that tables start with 1)ship = entityManager:entityData[1]-- nope, that crashed the program, with the same run-time error too...


As for checking for lua errors, I've been looking at various documents to understand exactly how to do it, but it's still very confusing to me.

Macbook Pro 2.66Ghz dual core, 4GB ram, 512MB vram, MacOSX 9.1, Windows 8.1
Xcode 5.0.2, C++, lua

I haven't used that particular feature of Luabind, but I'm not sure that it's intended to facilitate C-style indexed element access like in your example.

Have you looked at the example given here? In that example, a for loop is used to iterate over the elements in the container, which I imagine is more in keeping with the intended usage of that particular feature.

As for direct element access like you're trying to do, I haven't attempted that myself so I can't really comment further - maybe someone else will be able to though.
You can do it one of two ways:

You can set the metatable to intercept indexing attempts, and if it is a number, grab stuff out of the vector. This method would 'work', but seems kinda silly.

I would go ahead and just wrap vector element access in a function like "at" or "get" via .def("get", &std::vector<T>::operator[]) or something.

[size=1]Visit my website, rawrrawr.com

I like the idea of wrapping the vector class. In fact I just remembered that I forgot that I have this binding code for an std::vector:

class_<std::vector<int> >("ivector")	 .def(constructor<>())	 .def("push_back", &std::vector<int>::push_back)	 .def("at",(int&(std::vector<int>::*)(size_t))&std::vector<int>::at),


I got this from a google search result. I noticed that it seems to be specifically for an array of integers. Would I need to make it like this?
class_<std::vector<entity> >("vector")


or...
class_<std::vector<class> >("vector")

Macbook Pro 2.66Ghz dual core, 4GB ram, 512MB vram, MacOSX 9.1, Windows 8.1
Xcode 5.0.2, C++, lua

Yeah, since lua has no concepts of templates, you'll have to bind each instance of std::vector<> that you have.

It would look like the first one (class_<std::vector<entity> >("vector"))

[size=1]Visit my website, rawrrawr.com

Binding the vector didn't work, compiler errors.

I think I have an idea though. Would it work if I made a lua table with each element as an instance of my entity class and modified each entity when it needed to?

If that does work there is one last thing to consider. Getting the updated classes back into C++.

Here is an example of how I get an integer from lua to C++:
// my script class is named scrscr.doString("incomingGlobalVariable = gameManager.resWidth");gameManager.toggleResWidth(luabind::object_cast<int>(luabind::globals(L)["incomingGlobalVariable"]));


Would I update my entities something like this?
       scr.doString("incomingGlobalVariable = entityTable[1]");       entityManager.entityData[0] = luabind::object_cast<int>(luabind::globals(L)["incomingGlobalVariable"]);

Macbook Pro 2.66Ghz dual core, 4GB ram, 512MB vram, MacOSX 9.1, Windows 8.1
Xcode 5.0.2, C++, lua

Still, nothing is working.

Last night I tried to create a new lua table every time the constructor for my entity class was called.
It didn't work, I got a BAD ACCESS runtime error.

This morning I got an idea to create these update functions. The first argument would tell my engine the position in the vector, and then I would give it the information I wanted to update...

That didn't work either.

My game engine won't work without being able to access the data that's created, but every attempt to work around the errors fails.

Has anyone made, or seen a working asset managing class that could properly exchange data with lua through luabind?

Macbook Pro 2.66Ghz dual core, 4GB ram, 512MB vram, MacOSX 9.1, Windows 8.1
Xcode 5.0.2, C++, lua

This topic is closed to new replies.

Advertisement