OOP help
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
- Zilarrezko
- Party member
- Posts: 345
- Joined: Mon Dec 10, 2012 5:50 am
- Location: Oregon
OOP help
So I've pretty much got a ton of LUA down, but I think one of the last things I need to learn is Object Orientated Programming in LUA. I've seen about 6 videos that use it in some way shape or form (tutorial or application), and 3 written tutorials or manuals (one from a book), yet I can't wrap my head around it enough to apply any of it to a game or even in a simple console program. If anyone has a reference that explains it VERY well please let me know so I can stop hitting my head against a brick wall.
Re: OOP help
For the record, it's Lua, not LUA.
Also for the record, if you're not comfortable with OOP, you don't really need to learn it. There are plenty of different non-oop programming style and you can choose to make your game however you want, as long as it works.
On topic, OOP in Lua is usually based on tables, the "colon syntax", and using the __index metamethod for inheritance. Inheritance is the ability to create an instance of another object, or another table in this case, completely separate from the main table, which uses the functions of its parents.
Here's a simple example:
You can learn more about it on the lua-users wiki: http://lua-users.org/wiki/ObjectOrientationTutorial
Also for the record, if you're not comfortable with OOP, you don't really need to learn it. There are plenty of different non-oop programming style and you can choose to make your game however you want, as long as it works.
On topic, OOP in Lua is usually based on tables, the "colon syntax", and using the __index metamethod for inheritance. Inheritance is the ability to create an instance of another object, or another table in this case, completely separate from the main table, which uses the functions of its parents.
Here's a simple example:
Code: Select all
Person = {}
Person.__index = Person -- this makes it so that instances access this table
-- same as
-- function Person.talk(self)
function Person:talk()
print("Hello, my name is " .. self.name)
end
function Person.new(name)
local instance = {} -- create a new instance
setmetatable(instance, Person) -- derive it from the person class
instance.name = name -- set the name of the instance
return instance -- return the new instance
end
-- making a new instance of Person
jason = Person.new("Jason")
-- same as
-- jason.talk(jason)
jason:talk() --prints: Hello, my name is Jason
- Zilarrezko
- Party member
- Posts: 345
- Joined: Mon Dec 10, 2012 5:50 am
- Location: Oregon
Re: OOP help
I can understand that code just fine, it's just I can't write my own for an application because everything is pointing everywhere and it literally gives me a headache trying to understand it, let alone beginning to think about what code to write to do what I want as an application.
I've read that tutorial twice before and it just doesn't help me. As for a different approach to doing a task other than OOP, I can't think of any other way to do so.
I've read that tutorial twice before and it just doesn't help me. As for a different approach to doing a task other than OOP, I can't think of any other way to do so.
Re: OOP help
What is it about OOP that confuses you? You're being a little vague. Also, hat is it that you're trying to do? Are you sure you absolutely need to learn OOP to accomplish it?
There are plenty of alternatives to OOP. An alternative to the example code I've provided:
A suggestion I'd make is to look at the code in some others' games, to get a good idea of the kind of design patterns you can implement in a game. You'll find OOP 7 out of 10 times, but if you look deep enough, you'll also find a lot of neat coding techniques for yourself.
There are plenty of alternatives to OOP. An alternative to the example code I've provided:
Code: Select all
function newPerson(name)
return {
name = name,
talk = function(self)
print("Hello, my name is " .. self.name)
end,
}
end
jason = newPerson("Jason")
jason:talk()
- Zilarrezko
- Party member
- Posts: 345
- Joined: Mon Dec 10, 2012 5:50 am
- Location: Oregon
Re: OOP help
I'm not sure what i'm having trouble with, and it's severely frustrating. As with your suggestion, trust me, I've seen a lot of videos
I've used Goature's entity system, and I can trace every bit of code, but it makes me hit my head against the wall that I can't create my own from scratch, of which I want to do and he never explains anything here:
http://www.youtube.com/watch?v=L9G0WyG9vaY
I've looked at this video about 4 times, but I can't figure out from 17:10 and on (you can see a couple of my comments in the video of me being distressed that I don't understand both the code and what I'm not understanding):
http://www.youtube.com/watch?v=SDLujCr0c5Y
And I've watched the following video 3 times trying to make my GUI system even starting but I seem to have trouble even making a function return two values which makes me . I don't even know where to begin in what is confusing for me there:
http://www.youtube.com/watch?v=ppZMCAF7cWw
And I've seen this one once, but he's too confusing to follow his words.
http://www.youtube.com/watch?v=GcKCAdc0WZ8
It might be because nobody explains their code, they just say "well here it is, this goes through here creating these values, and this is an OOP system". Yet no one really says this is how you create a set of base code, this is how an instance is create. This is how you can tell this instance from this other instance and here's how you access this specific instance's properties. I might have no clue what I'm talking about in which case no one can help me and I've wasted your time, of which I'm sorry if that's the case. I may take the day and tomorrow just to see what i'm not getting wrong. Just spent the past 4 months looking at code and OOP systems along with AP Physics, might not be bad to take a step back for a couple days too.
I've used Goature's entity system, and I can trace every bit of code, but it makes me hit my head against the wall that I can't create my own from scratch, of which I want to do and he never explains anything here:
http://www.youtube.com/watch?v=L9G0WyG9vaY
I've looked at this video about 4 times, but I can't figure out from 17:10 and on (you can see a couple of my comments in the video of me being distressed that I don't understand both the code and what I'm not understanding):
http://www.youtube.com/watch?v=SDLujCr0c5Y
And I've watched the following video 3 times trying to make my GUI system even starting but I seem to have trouble even making a function return two values which makes me . I don't even know where to begin in what is confusing for me there:
http://www.youtube.com/watch?v=ppZMCAF7cWw
And I've seen this one once, but he's too confusing to follow his words.
http://www.youtube.com/watch?v=GcKCAdc0WZ8
It might be because nobody explains their code, they just say "well here it is, this goes through here creating these values, and this is an OOP system". Yet no one really says this is how you create a set of base code, this is how an instance is create. This is how you can tell this instance from this other instance and here's how you access this specific instance's properties. I might have no clue what I'm talking about in which case no one can help me and I've wasted your time, of which I'm sorry if that's the case. I may take the day and tomorrow just to see what i'm not getting wrong. Just spent the past 4 months looking at code and OOP systems along with AP Physics, might not be bad to take a step back for a couple days too.
Re: OOP help
You're making this harder than it actually is. OOP is really just about extending a set of functions and data. I mean, this is essentially OOP in Lua:
If any of that confuses you let me know.
Code: Select all
-- OOP Library. Open source license. Send donations to Kadoba. Do not steal.
function inherit( parent, child )
child = child or {}
for k,v in pairs( parent ) do child[k] = v end
return child
end
new = inherit
- kikito
- Inner party member
- Posts: 3153
- Joined: Sat Oct 03, 2009 5:22 pm
- Location: Madrid, Spain
- Contact:
Re: OOP help
Ok. Brace yourself, this is going to be long.
---
The thing is that OOP is an overused, "bag term" that people use with many different meanings. Let me explain the ones I see more often.
Pure OOP: Objects
On its simplest form, OOP means "Programming using objects". On its purest form, an object is just "A group of attributes and some functions that act on those attributes". These "functions that act on attributes" are usually called methods.
Given that definition, you could create an object in Lua very easily:
On that example, peter is an object with 1 attribute (name) and 1 method (speak).
Classes (as instance creators)
"Class" is another of those "bag concepts" that people use with several different meanings. The one they tend to use the most is "something that, given some properties, can create an object". Objects created by a class are usually called instances of that class. The instances of a class usually "work similarly", since their methods do the same things (only their attributes are different). This is very useful in games, where you very often have similar things that behave the same way (enemy ships in a shooter game, the bullets, powerups ...)
With that definition of class, a simple Lua function could be a class:
So john and mary are now instances of Person. They both have an attribute called name and a method called speak.
Classes (as method repositories)
On the previous example, each instance of the class had its own copy of the speak method. While this works in certain scenarios, it is usually not very efficient in terms of speed (Lua creates functions very fast, but it still takes some time) and memory (there can be many copies of the same function). In other languages they have the same issue: it would be very desirable to put the methods in 1 place, and share them among all the instances. This task usually falls upon the classes too: they act as a "repository of methods". When an instance needs to invoke a method, it "requests it to the class", instead of having its own copy.
In Lua, this behavior is very easily accomplished with metatables & metamethods:
On this example, Person is able to create instances by using a function called new. jason and angelo are instances of Person, but they only have the name attribute. The speak method is on the Person class, and there's only one copy of it. This saves memory and instantiation speed, in exchange of making every invokation of the speak method a bit slower ("asking the class for the method" takes a bit of time, too).
Composition
One important thing that people tend to overlook is the fact that attributes are not limited to basic objects, like strings or numbers. An attribute can be an object, too. When an object X has another object Y as attribute, we say that X it is composed of Y, or that X has a Y.
On the previous example, Person instances have two attributes: name & parent (which can be nil). mogh has its parent set to nil, while worf has its parent set to morgh. The speak method, shared by both instances in the Person class, prints a different message depending on whether the instance invoking it has a parent attribute or not.
Notice that you can do composition with instances of different classes, too:
On this example there are two classes, Gun and Person.
Gun has two attributes, name & sound, and one method, fire. It has two instances, revolver & phaser.
Person has two attributes, name & gun, and one method, attack. It has two instances, flash (who uses a revolver) & ming (who uses a phaser).
Inheritance
Now this is something that trips people a lot. The relationship between a class and its instances is clear: we say "an instance IS A class": "peter IS A person".
There are some people that like to extend this to classes as well. They want to express things like, "A Mammal is an Animal", where both Mammal and Animal are classes with instances. And have Mammal "inherit" some properties from Animal, so that instances of Mammal "borrow" the methods of Animal in addition of those of Mammal. And they even want to extend this hierarchy with lots of levels: Bat is a Mammal is an Animal is a Vertebrate etc.
Defining relationships between classes with "is A" is difficult because a class can "be" many other things in the real world. A Mammal is a vertebrate, but it is also Solid. And is is also Visible. And needs food for living. The relationship between instances and their class is clear (the class creates the instances) but when you have 2 classes it's much more complex.
In my opinion, composition can usually express the same concepts as inheritance with more exactitude: a Mammal has a SolidBody, has a VisibleShape and has DietaryNeeds. For this reason, I am not going to show you how to do inheritance in Lua, which is possible, but is not really needed 90% of the time.
Conclusion
People mean very different things when they say "OOP". Most often it's enough to have classes that act as instance creators and method repositories. That can be done very easily with metamethods. It is very useful in games, where very often you need things that behave the same way but have slightly different properties.
I hope this explanation helps you get started. Good luck!
---
The thing is that OOP is an overused, "bag term" that people use with many different meanings. Let me explain the ones I see more often.
Pure OOP: Objects
On its simplest form, OOP means "Programming using objects". On its purest form, an object is just "A group of attributes and some functions that act on those attributes". These "functions that act on attributes" are usually called methods.
Given that definition, you could create an object in Lua very easily:
Code: Select all
local peter = {name = 'Peter', speak = function(self) print("Hi, I'm " .. self.name) end }
peter:speak() -- Hi, I'm Peter
Classes (as instance creators)
"Class" is another of those "bag concepts" that people use with several different meanings. The one they tend to use the most is "something that, given some properties, can create an object". Objects created by a class are usually called instances of that class. The instances of a class usually "work similarly", since their methods do the same things (only their attributes are different). This is very useful in games, where you very often have similar things that behave the same way (enemy ships in a shooter game, the bullets, powerups ...)
With that definition of class, a simple Lua function could be a class:
Code: Select all
local Person = function(name)
return {name = name, speak = function(self) print("Hi, I'm " .. self.name) end }
end
local john = Person('John')
local mary = Person('Mary')
john:speak() -- Hi, I'm John
mary:speak() -- Hi, I'm Mary
Classes (as method repositories)
On the previous example, each instance of the class had its own copy of the speak method. While this works in certain scenarios, it is usually not very efficient in terms of speed (Lua creates functions very fast, but it still takes some time) and memory (there can be many copies of the same function). In other languages they have the same issue: it would be very desirable to put the methods in 1 place, and share them among all the instances. This task usually falls upon the classes too: they act as a "repository of methods". When an instance needs to invoke a method, it "requests it to the class", instead of having its own copy.
In Lua, this behavior is very easily accomplished with metatables & metamethods:
Code: Select all
local Person = {}
Person.new = function(name) return setmetatable({name=name}, {__index=Person}) end
Person.speak = function(self) print("Hi, I'm " .. self.name) end
local jason = Person.new('Jason')
local angelo = Person.new('Angelo')
jason:speak() -- Hi, I'm Jason
angelo:speak() -- Hi, I'm Angelo
Composition
One important thing that people tend to overlook is the fact that attributes are not limited to basic objects, like strings or numbers. An attribute can be an object, too. When an object X has another object Y as attribute, we say that X it is composed of Y, or that X has a Y.
Code: Select all
local Person = {}
Person.new = function(name, parent) return setmetatable({name=name, parent=parent}, {__index=Person}) end
Person.speak = function(self)
if self.parent then
print("Hi, I'm " .. self.name .. ", son of " .. self.parent.name)
else
print("Hi, I'm " .. self.name)
end
end
local mogh = Person.new('Mogh')
local worf = Person.new('Worf', mogh)
mogh:speak() -- Hi, I'm Mogh
worf:speak() -- Hi, I'm Worf, son of Mogh
On the previous example, Person instances have two attributes: name & parent (which can be nil). mogh has its parent set to nil, while worf has its parent set to morgh. The speak method, shared by both instances in the Person class, prints a different message depending on whether the instance invoking it has a parent attribute or not.
Notice that you can do composition with instances of different classes, too:
Code: Select all
local Gun = {}
Gun.new = function(name, sound) return setmetatable({name=name, sound=sound}, {__index=Gun}) end
Gun.fire = function(self, target) print('<The ' .. self.name .. ' fires upon ' .. target.name .. '. ' .. self.sound .. '!>') end
local Person = {}
Person.new = function(name, gun) return setmetatable({name=name, gun=gun}, {__index=Person}) end
Person.attack = function(self, target)
print('Take this, ' .. target.name .. '!')
self.gun:soot(target)
end
local revolver = Gun.new('Revolver', 'Bang')
local phaser = Gun.new('Phaser', 'Zap')
local flash = Person('Flash', revolver)
local ming = Person('Ming', phaser)
flash:attack(ming) -- Take this, Ming! <The Revolver fires upon Ming. Bang!>
ming:attack(flash) -- Take this, Flash! <The Phaser fires upon Flash. Zap!>
On this example there are two classes, Gun and Person.
Gun has two attributes, name & sound, and one method, fire. It has two instances, revolver & phaser.
Person has two attributes, name & gun, and one method, attack. It has two instances, flash (who uses a revolver) & ming (who uses a phaser).
Inheritance
Now this is something that trips people a lot. The relationship between a class and its instances is clear: we say "an instance IS A class": "peter IS A person".
There are some people that like to extend this to classes as well. They want to express things like, "A Mammal is an Animal", where both Mammal and Animal are classes with instances. And have Mammal "inherit" some properties from Animal, so that instances of Mammal "borrow" the methods of Animal in addition of those of Mammal. And they even want to extend this hierarchy with lots of levels: Bat is a Mammal is an Animal is a Vertebrate etc.
Defining relationships between classes with "is A" is difficult because a class can "be" many other things in the real world. A Mammal is a vertebrate, but it is also Solid. And is is also Visible. And needs food for living. The relationship between instances and their class is clear (the class creates the instances) but when you have 2 classes it's much more complex.
In my opinion, composition can usually express the same concepts as inheritance with more exactitude: a Mammal has a SolidBody, has a VisibleShape and has DietaryNeeds. For this reason, I am not going to show you how to do inheritance in Lua, which is possible, but is not really needed 90% of the time.
Conclusion
People mean very different things when they say "OOP". Most often it's enough to have classes that act as instance creators and method repositories. That can be done very easily with metamethods. It is very useful in games, where very often you need things that behave the same way but have slightly different properties.
I hope this explanation helps you get started. Good luck!
Last edited by kikito on Tue Feb 11, 2014 11:33 am, edited 2 times in total.
When I write def I mean function.
- Zilarrezko
- Party member
- Posts: 345
- Joined: Mon Dec 10, 2012 5:50 am
- Location: Oregon
Re: OOP help
uh... k... I don't see what setting a index equal to the table of which the index is in does, and I'm guessing in making the first argument in setmetatable with {name = name, parent=parent} is creating a table with those values. To be honest I might be more confused now than when I started.Why would I create a metatable for each time I create a new instance?
So let's say I want to create an entity system (not the only that goature did, because I copied that crap) I have a table and I want to create a prototype, or rather a foundation for each instance.
so then in that code, would t.james have t.james.id = 0?
I just don't see how I would use speak or even how to use classes. It's like giving a child a crayon. You draw a line on a piece of paper and then you give the child the crayon and he sticks it up his nose. I can copy someones code, and I can run through it and explain it... a little. But If I was to ask to write my own code, I'm pretty much just going to be the child sticking a crayon up my ass.
So let's say I want to create an entity system (not the only that goature did, because I copied that crap) I have a table and I want to create a prototype, or rather a foundation for each instance.
Code: Select all
t = {
}
prototype = {
__index = {
x = 0,
y = 0,
id = 0
}
}
setmetatable(t, prototype)
t.james = {
}
I just don't see how I would use speak or even how to use classes. It's like giving a child a crayon. You draw a line on a piece of paper and then you give the child the crayon and he sticks it up his nose. I can copy someones code, and I can run through it and explain it... a little. But If I was to ask to write my own code, I'm pretty much just going to be the child sticking a crayon up my ass.
Re: OOP help
Now we're getting somewhere.
We actually used three tables here. One for the normal table, one for the metatable, and one for the __index. Well, there's nothing stopping us from using one table for both the metatable AND the __index.
There's really nothing wrong with either way but using a single table for both is typically cleaner and more often used.
Let's take a step back here. You probably understand now that __index will be checked if the values aren't found in the original table. You shouldn't have any problems understanding this:Zilarrezko wrote:uh... k... I don't see what setting a index equal to the table of which the index is in does,
Code: Select all
local meta = {
__index = { key = "value" }
}
local t = {}
setmetatable(t, meta)
-- now t.key results in "value"
Code: Select all
local meta = { key = "value" }
meta.__index = meta
local t = {}
setmetatable(t, meta)
-- t.key still results in "value"
The first argument in setmetatable is not the metatable. It's the table you want to assign the metatable to. In otherwords, THAT is your new "instance". The function setmetatable also returns the table as well as assigning it. So both of the following peices of code do the same thing:I'm guessing in making the first argument in setmetatable with {name = name, parent=parent} is creating a table with those values. To be honest I might be more confused now than when I started. Why would I create a metatable for each time I create a new instance?
Code: Select all
local instance = {}
setmetatable(instance, meta)
Code: Select all
local instance = setmetatable({}, meta)
You've almost got it here. The problem is that you are assigning the metatable to t and not t.james.So let's say I want to create an entity system (not the only that goature did, because I copied that crap) I have a table and I want to create a prototype, or rather a foundation for each instance.
so then in that code, would t.james have t.james.id = 0?Code: Select all
t = { } prototype = { __index = { x = 0, y = 0, id = 0 } } setmetatable(t, prototype) t.james = { }
I just don't see how I would use speak or even how to use classes. It's like giving a child a crayon. You draw a line on a piece of paper and then you give the child the crayon and he sticks it up his nose. I can copy someones code, and I can run through it and explain it... a little. But If I was to ask to write my own code, I'm pretty much just going to be the child sticking a crayon up my ass.
Code: Select all
t = {
}
prototype = {
__index = {
x = 0,
y = 0,
id = 0
}
}
t.james = setmetatable({}, prototype)
- Zilarrezko
- Party member
- Posts: 345
- Joined: Mon Dec 10, 2012 5:50 am
- Location: Oregon
Re: OOP help
So now I need to create some type of function that when I call it it creates a new instance in the table "t".
but I believe if I try and do...
i'll probably get some type of error for some reason, probably because t.new is a function and the function doesn't very well have a v.text. So I should make a whole new table for the objects to store in? So...
So now I have a place where I can go through a for loop and not get any problems?
Code: Select all
t = {
}
prototype = {
__index = {
x = 0,
y = 0,
text = "banana"
}
}
id = 0
t.new = function()
t[1 + id] = setmetatable({}, prototype)
id = id + 1
end
Code: Select all
local var = 10
for k,v in pairs(t) do
love.graphics.print(v.text,v.x,v.y + var)
var = var + 16
end
Code: Select all
t = {
}
objects = {
}
prototype = {
__index = {
x = 0,
y = 0,
text = "banana"
}
}
id = 0
t.new = function()
objects[1 + id] = setmetatable({}, prototype)
id = id + 1
end
Who is online
Users browsing this forum: No registered users and 7 guests