Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411283 Posts in 69325 Topics- by 58380 Members - Latest Member: bob1029

March 29, 2024, 02:06:33 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsCommunityTownhallForum IssuesArchived subforums (read only)TutorialsC++ class derivation in Lua
Pages: [1] 2
Print
Author Topic: C++ class derivation in Lua  (Read 16455 times)
diwil
Level 2
**


View Profile WWW
« on: October 07, 2008, 12:48:57 AM »

Dear TIGers, I am here to demonstrate you the means to create a base class in C++ and using the luabind library, implement said class in your Lua, and enable you to create subclasses of such class. This will enable you to create a basic entity in your game engine code, and specify different logic for each of the subclasses.

First off, lets start with getting Lua, and luabind fired up:
Code:
// The Setup
lua_State* L = lua_open(); // create the Lua state
luaL_openlibs(L); // open all of the basic libraries so we can use them
luabind::open(L); // register luabind to our Lua state
I've omitted any error checking from above, but I assume you'll know how to implement those yourself. The code should be pretty self-explanatory.

Next, lets define our class:
Code:
class Foo {
public:
// The Constructor
// @self the reference to our Lua instance so we may reference to our Lua object in C++
// and call the Lua class methods via luabind::call_member<void>(m_Self, "function");
// @name an arbitrary test value, to identify our objects
Foo(luabind::object self, const char* name) : m_Self(self), m_Name(name) {
// Declare ourselves openly!
std::cout << m_Name << " created." << std::endl;
}

// The Destructor
~Foo(void) {
// Declare to the world that we no longer exist
std::cout << m_Name << " destroyed." << std::endl;
}

// This method will be overridden in Lua
void Think() {
std::cout << m_Name << " is thinking." << std::endl; // Output something generic
}

// This method will enable us to reference to another object, and alter it's values
// @target the reference to another Foo object
void Kill(luabind::object target) {
// Check if our target is a valid object
if (target && luabind::type(target) != LUA_TNIL) {
// Convert the luabind::object into our own class type
// notice the pointer form so we'll get just that, rather than a copy
Foo* target_foo = luabind::object_cast<Foo*>(target);
std::cout << m_Name << " attacks " << target_foo->m_Name << "!" << std::endl;

// Lets alter the target's properties
target_foo->m_Name = "Dead";
}
}

// Class attributes
luabind::object m_Self; // Reference to our own Lua object
std::string m_Name; // Our object's name
};
The code above is also pretty self-explanatory, as I attempted to explain everything in the comments. The things you need to know are the type luabind::object, which is a wrapper for all of Lua's data types, so we can access those types in C++.

The basic constructor takes two parameters, a Lua object, and a string for a name. This default class constructor is called from Lua via the function super(), which lets us access parent methods in classes. Next off, lets see how we can bind this class into Lua with the marvelous luabind:
Code:
luabind::module(L) [
luabind::class_<Foo>("Foo")
.def(luabind::constructor<luabind::object, const char*>())
.def("Think", &Foo::Think)
.def("Kill", &Foo::Kill)
.def_readwrite("name", &Foo::m_Name)
];
Now, this piece of code needs a little explaining to do. By luabind::module(), we can define functions, classes and variables to Lua and it's namespaces. I highly recommend reading through luabind's documentation to understand how all of this works.

But what we're doing now, is we first bind the class Foo into the Lua state L, via the luabind::class_<>() template method, followed by a chain of def() and def_readwrite() calls to specify the classes functionality and variables. The important row to check out is the line defining the constructor, where you'll have to specify the exact same parameters into the template; I wasn't able to create multiple constructors in C++, and I'm not sure if this is even possible. The member attribute m_Name will take the form of name in Lua, and so-forth.

Now, onto the Lua code:
Code:
-- First, define the two new subclasses of Foo
class 'Bar' (Foo)
class 'Baz' (Foo)

-- Bar's constructor, notice the super() method on the first row
function Bar:__init(name)
super(self, name); -- Call for Foo::Foo(self, name)
print("A " .. self.name .. " a day keeps the doctor away.");
end

-- Bar's overloading method for Think()
function Bar:Think()
print(self.name .. " is cool.");
end

-- Baz's constructor, the same method for super() applies as to Bar
function Baz:__init(name)
super(self, name); -- Call for Foo::Foo(self, name)
print("A " .. self.name .. " is a wonderful thing, don't you think?");
end

-- Create a bar
bar = Bar("Barry");
bar:Think();

-- Create a baz
baz = Baz("Bazzy");
baz:Think();

-- Battle to the DEATH!
baz:Kill(bar);
bar:Think();
Now, this segment I'll explain in greater detail. First off, we declare our two new classes derived from Foo, the class Bar and Baz. We then define a new constructor for Bar through Bar:__init(), which calls for Foo's constructor through the function super(), initializing the class in C++ and setting the name and whatnot. After this, we display a small message to see if our new derived constructor worked.

We also define a new Think() method for Bar, by simply declaring an overloading function for it. The same is applied for Baz, minus the overloading Think() method, which will cause Baz to call Foo's Think() method. Quite simple, really.

Now, you can run the Lua script with the function luaL_dofile(), as such:
Code:
if (luaL_dofile(L, "foo.lua")) {
std::cout << "We hit a little snug: " << lua_tostring(g_LuaState, -1) << std::endl; // Print out the error message
}
Now, if everything is correct, when you execute the program built from these little snippets, your output would look something like this:
Code:
Barry created.
A Barry a day keeps the doctor away.
Barry is cool.
Bazzy created.
A Bazzy is a wonderful thing, don't you think?
Bazzy is thinking.
Bazzy attacks Barry!
Dead is cool.
Bazzy destroyed.
Dead destroyed.
So, we created our new Bar, "Barry", and our Baz, "Bazzy", then went on to have Bazzy attack Barry, resulting in Barry changing his name to "Dead."

It is important to notice, that the object destructors are called only during the garbage collection phase, so make sure you close your Lua state before exiting the program, otherwise you'll encounter some memory loss and bad things will happen.

Now, that was all for now, I hope that was helpful to some of you and if you have any questions, suggestions for improvements or errors to correct, please do. Smiley
« Last Edit: March 19, 2009, 09:08:20 PM by Derek » Logged
Hideous
That's cool.
Level 10
*****


3D models are the best


View Profile WWW
« Reply #1 on: October 07, 2008, 12:55:34 AM »

I didn't even know you could use classes in Lua. I thought it was not object-oriented?
Logged

diwil
Level 2
**


View Profile WWW
« Reply #2 on: October 07, 2008, 12:59:52 AM »

Lua does have OOP capabilities, but not in the traditional sense. The typing in Lua is dynamic, so things can be many things at once; an object in Lua basically has the same capabilities as a structure in pure C.

This is one of the reasons why I like Lua as a language; the flexibility enables me to do things with it that would rely on heavy templating with C++.
Logged
Moosader
Level 0
***


View Profile WWW
« Reply #3 on: October 07, 2008, 09:25:50 AM »

Oh shit!  Hi, Santa.  Didn't know you had joined. Tongue
Logged

diwil
Level 2
**


View Profile WWW
« Reply #4 on: October 07, 2008, 09:27:02 AM »

Hey Spoonie, yeah I joined a little time ago. Smiley
Logged
David Pittman
Level 2
**


MAEK GAEM


View Profile WWW
« Reply #5 on: October 07, 2008, 01:14:02 PM »

Nice introduction to luabind. I was looking into this last year and was a bit scared off by the binding syntax, but it really doesn't look so difficult the way you've presented it. I may have to revisit this for my next project.
 Beer!
Logged

Cymon
Level 9
****


Computer Kid


View Profile WWW
« Reply #6 on: October 07, 2008, 01:37:38 PM »

A guy on my site wants to use Lua in one of his programs. Just one more thing I should be checking out. Man I wish I could do this for a living. Or at least the way I used to when I was a student.
Logged

Cymon's Games, free source code, tutorials, and a new game every week!
Follow me on twitter
diwil
Level 2
**


View Profile WWW
« Reply #7 on: October 07, 2008, 09:36:05 PM »

Nice introduction to luabind. I was looking into this last year and was a bit scared off by the binding syntax, but it really doesn't look so difficult the way you've presented it. I may have to revisit this for my next project.
 Beer!
Yeah, the suntax was horrid when I first took a look at it, but after a few days it all started to make sense. Smiley

It's a shame luabind's manual doesn't have a reference chapter, so they don't cover half of the API's calls.
Logged
Hajo
Level 5
*****

Dream Mechanic


View Profile
« Reply #8 on: October 08, 2008, 01:47:47 AM »

Nice introduction to luabind. I was looking into this last year and was a bit scared off by the binding syntax, but it really doesn't look so difficult the way you've presented it.
 Beer!

I've been using Lua in one of my former projects, too, and also was scared of the thing. So I wrote a very simple binding by myself. It worked for the project, but it's definitely good to see how it's done right. Thank you for the tutorial Smiley
Logged

Per aspera ad astra
diwil
Level 2
**


View Profile WWW
« Reply #9 on: October 08, 2008, 01:52:05 AM »

You're welcome! Smiley

I used mostly luabind to see how it's done, but I'm not certain if I'll keep luabind in the project as is, if I manage to write my own definition of the functionality. I mean, having 8MB of extra sources in my project (and thus inflating my executable size) isn't something I enjoy, especially when it comes to compile times (I transfer my files back and forth between platforms through email every day, and the object files for the debug version tend to bloat).

I'll study Lua's own binding functions further next week, to see how I'll be able to implement the class binding on my own. I'll surely attach the results in the first post if I figure it out. Beer!
Logged
Hajo
Level 5
*****

Dream Mechanic


View Profile
« Reply #10 on: October 08, 2008, 02:00:27 AM »

8MB! That looks massive.

When I did it, I decided for a more procedural notation style.

There were objects, but the notation was not

Code:
object_variable:method_name(parameter_list)

but

Code:
method_name(object_variable, parameter_list)

That seemed easier to create bindings for, and worked about as well. But Lua is a nice and efficient scripting language. I liked it much.
Logged

Per aspera ad astra
muku
Level 10
*****


View Profile
« Reply #11 on: October 08, 2008, 02:06:27 AM »

Thanks for taking the time to write this.

I mean, having 8MB of extra sources in my project (and thus inflating my executable size) isn't something I enjoy

It's that huge? Shocked 8MB of source code sounds... hard to believe, to be honest.


Quote
I transfer my files back and forth between platforms through email every day, and the object files for the debug version tend to bloat

Have you considered using code versioning software with a (free) online repository? I personally use Mercurial (a distributed CVS) with a repository at assembla.com, and it works like a charm for alternating between working at home and on the road (erm, train). I can even hack on something while riding on the train, push the changeset onto my USB stick, and commit it into my main repository when I'm home. It's incredibly useful.

Besides all the other advantages you get from using a versioning system: incremental backups, an automatic development log via commit messages, tagging of release versions... I wouldn't want to live without it anymore.

Maybe, if some people are interested, I could write a tutorial on using these things since we now have this shiny new Tutorials section? I've found that many (especially amateur) developers are a bit scared of using such a system, but it's really not that complicated and a huge productivity boost.
Logged
diwil
Level 2
**


View Profile WWW
« Reply #12 on: October 08, 2008, 02:15:20 AM »

Code:
object_variable:method_name(parameter_list)

but

Code:
method_name(object_variable, parameter_list)

That seemed easier to create bindings for, and worked about as well. But Lua is a nice and efficient scripting language. I liked it much.
That's a very nice tip! I think calling class methods isn't too hard, just a matter of pushing the class to the stack, probably figuring out the method name from the metatable, and then executing it as you'd call a normal function.

How'd you do the class definition without luabind?

It's that huge? Shocked 8MB of source code sounds... hard to believe, to be honest.
Yeah, luabind uses the boost library, which has... Needless to day, a crapload of stuff. I could probably strip things down, but the broken-dependency battle is not something high on my priority list. :D
Logged
george
Level 7
**



View Profile
« Reply #13 on: October 08, 2008, 05:00:36 PM »

Besides all the other advantages you get from using a versioning system: incremental backups, an automatic development log via commit messages, tagging of release versions... I wouldn't want to live without it anymore.

Maybe, if some people are interested, I could write a tutorial on using these things since we now have this shiny new Tutorials section?

muku, I would definitely like to see that. I just started using bazaar w/ launchpad and really like it, but it took me a long time to figure it out/get it working right. There seems to be a lack of really basic tutorials on this kind of stuff, it's all advanced or very minimal information.
Logged
increpare
Guest
« Reply #14 on: October 08, 2008, 05:29:25 PM »

Besides all Maybe, if some people are interested, I could write a tutorial on using these things since we now have this shiny new Tutorials section?
muku, I would definitely like to see that.
Ditto.  though I should be able to figure it out myself, it's looking like I'm never going to get around to getting into the swing of versioning without external influence.
Logged
diwil
Level 2
**


View Profile WWW
« Reply #15 on: October 08, 2008, 09:02:24 PM »

I can post up a subversion tutorial, when I get my server box up and running. Smiley
Logged
Hajo
Level 5
*****

Dream Mechanic


View Profile
« Reply #16 on: October 09, 2008, 12:09:37 AM »

If you have several workplaces and want to keep them in sync without using a network connection between them, a CVS or SVN repository on an USB stick can help a lot.
Logged

Per aspera ad astra
diwil
Level 2
**


View Profile WWW
« Reply #17 on: October 09, 2008, 01:02:18 AM »

That's a brilliant idea! Shocked
Logged
muku
Level 10
*****


View Profile
« Reply #18 on: October 09, 2008, 09:08:22 AM »

If you have several workplaces and want to keep them in sync without using a network connection between them, a CVS or SVN repository on an USB stick can help a lot.

That's basically what distributed SCMs are intended for, though. Can you even have a SVN repository without a SVN server to handle it?

There seems to be some interest in a tutorial on these things, so I might write one. Then again, Lynchpin seems to want to do one on SVN, so that may already fill that need? But then again, I strongly prefer distributed SCMs these days, and this might be a good chance to introduce their advantages to people here. I'll see if I have time to write something up.
Logged
David Pittman
Level 2
**


MAEK GAEM


View Profile WWW
« Reply #19 on: October 09, 2008, 11:06:58 AM »

Can you even have a SVN repository without a SVN server to handle it?

Of course! I just run my SVN repository on my hard drive. (And then I make regular backups to an external drive because having a single point of failure for my local files and the repository is bad.) It wouldn't work for multiple users, but it's great for a single-user versioning solution.
Logged

Pages: [1] 2
Print
Jump to:  

Theme orange-lt created by panic