Page 18 of 25

Re: middleclass & middleclass-extras: OOP for LUA

Posted: Sat Jun 18, 2011 10:54 am
by BlackBulletIV
Well I remember having trouble somewhere with them, possibly in plain Lua. But, they don't provide any benefit and can cause problems some times, so I wouldn't use them.

Re: middleclass & middleclass-extras: OOP for LUA

Posted: Sat Jun 18, 2011 3:25 pm
by bartbes
Yeah, they are only in there for legacy support and it only works in love, I guess we should take them out sometime..

Re: middleclass & middleclass-extras: OOP for LUA

Posted: Sat Jun 18, 2011 7:09 pm
by Kadoba
Noooooo... :(

Re: middleclass & middleclass-extras: OOP for LUA

Posted: Tue Jun 28, 2011 9:17 pm
by LuaWeaver
Wait a minute---
wait.

I understand OOP now :3. Everything is just a table with "children" that can have things other then "children" such as functions and values and even subclasses mixed in with those and those can have subclasses and those...

*dies*

Re: middleclass & middleclass-extras: OOP for LUA

Posted: Tue Jun 28, 2011 9:46 pm
by BlackBulletIV
I'm not completely sure whether what you're thinking of is OOP (are you just trying to give the impression of confusion?), but yes, OOP is a very abstract concept, usually being rather hard to wrap your head around.

Re: middleclass & middleclass-extras: OOP for LUA

Posted: Tue Jun 28, 2011 10:00 pm
by LuaWeaver
BlackBulletIV wrote:I'm not completely sure whether what you're thinking of is OOP (are you just trying to give the impression of confusion?), but yes, OOP is a very abstract concept, usually being rather hard to wrap your head around.
Yes, difficult. I only now understand. Table in tables in tables. Sorry about the wording, I'm used to Roblox OOP.

Re: middleclass & middleclass-extras: OOP for LUA

Posted: Wed Jun 29, 2011 5:35 am
by Robin
LuaWeaver wrote:Table in tables in tables.
No, that's Inception. :P

Re: middleclass & middleclass-extras: OOP for LUA

Posted: Wed Jun 29, 2011 7:20 am
by BlackBulletIV
LuaWeaver wrote:Table in tables in tables.
In Lua it would be metatables actually.

Re: middleclass & middleclass-extras: OOP for LUA

Posted: Wed Jun 29, 2011 7:37 am
by Jasoco
Robin wrote:
LuaWeaver wrote:Table in tables in tables.
No, that's Inception. :P
No, that's Xzibit.

Re: middleclass & middleclass-extras: OOP for LUA

Posted: Wed Jun 29, 2011 10:27 am
by kikito
LuaWeaver wrote:Wait a minute---
wait.

I understand OOP now :3. Everything is just a table with "children" that can have things other then "children" such as functions and values and even subclasses mixed in with those and those can have subclasses and those...

*dies*
It's a bit more complex than that ... and more simple too.

OOP has two main concepts: classes and instances.

Classes are just a bunch of properties - mostly functions.

When you create a class, you do it because you need a way to represent "common properties shared by a bundh of elements in your game". Those "elements", are usually the "instances" of the class. The "properties" are usually functions.

For example, if you are going to create a game with lots of balls bouncing around. A first approach using simple tables (no oop) could be this one:

Code: Select all

function love.load()
  ball1 = { x=100, y=100 }
  ball2 = { x=200, y=100 }
  ball3 = { x=300, y=100 }
end

function love.draw()
  love.graphics.circle('line', ball1.x, ball1.y, 100)
  love.graphics.circle('line', ball2.x, ball1.y, 100)
  love.graphics.circle('line', ball3.x, ball1.y, 100)
end
Imagine that now you want to have a different radius for each ball. You could do it like this:

Code: Select all

function love.load()
  ball1 = { x=100, y=100, radius = 10 }
  ball2 = { x=200, y=100, radius = 20 }
  ball3 = { x=300, y=100, radius = 30 }
end

function love.draw()
  love.graphics.circle('line', ball1.x, ball1.y, ball1.radius)
  love.graphics.circle('line', ball2.x, ball1.y, ball2.radius)
  love.graphics.circle('line', ball3.x, ball1.y, ball3.radius)
end

Creating balls starts getting complicated when start needing more properties. For example, a color. It makes sense to have a createBall function so you don't have to type that much. And you will probably want a "drawBall" function too:

Code: Select all

function createBall(x,y,radius,color)
  return {x=x, y=y, radius=radius, color=color}
end
function drawBall(ball)
  love.graphics.setcolor(unpack(ball.color))
  love.graphics.circle('line', ball.x, ball.y, ball.radius)
end

function love.load()
  ball1 = createBall(100, 100, 10, { 255,   0,   0 })
  ball2 = createBall(200, 100, 20, {   0, 255,   0 })
  ball3 = createBall(300, 100, 30, {   0,  0, 255 })
end

function love.draw()
  drawBall(ball1)
  drawBall(ball2)
  drawBall(ball3)
end
Remember what I told you about classes? They are thought to "group together" common properties (functions) of elements.

Look at createBall and drawBall. Don't they seem to be somehow "shared" by ball1, ball2 and ball3?

If we were to use OOP with this program, ball1, ball2 and ball3 would be instances of a class; and usually that class would be called Ball. createBall and drawBall would be methods of Ball; Since drawBall is going to be part of Ball, we can simply call it "Ball:draw" (instead of "Ball:drawBall"). For implementation reasons, createBall will get transformed into a method called "initialize" - that's just how it should be called in middleclass. Also, inside those methods, the "ball" parameter will be replaced by a parameter called "self". Let me show you:

Code: Select all

require 'middleclass'

Ball = class('Ball')

function Ball:initialize(x, y, radius, color) -- this was createBall
  self.x, self.y, self.radius, self.color = x, y, radius, color
end

function Ball:draw() -- this was drawball
  love.graphics.setcolor(unpack(self.color))
  love.graphics.circle('line', self.x, self.y, self.radius)
end

function love.load()
  ball1 = Ball:new(100, 100, 10, { 255,   0,   0 })
  ball2 = Ball:new(200, 100, 20, {   0, 255,   0 })
  ball3 = Ball:new(300, 100, 30, {   0,  0, 255 })
end

function love.draw()
  ball1:draw()
  ball2:draw()
  ball3:draw()
end
It doesn't look like much. But there are several things going on here. First, the amount of global variables used has been reduced. That is always good. Second, ball1:draw(...) works. That's because ball1, ball2, and ball3 are built so that they "know how to ask" their class (Ball) for its methods. If you add another method to Ball (for example, Ball:update), and it will also be shared by ball1, ball2, and ball3.

So that's the first part of OOP, in a very simple way: common functions go into a class, and specifics (like the x coordinate or the color) go into the instances. The instances "ask their class for help" when needed.

But that is not all.

A class can have a "superclasses" (a "father", if you want) and "subclasses" (the "children"). (A class could have no parents or children though).

When a class A is a subclass of class B, it's also common to say that is "inherits" from B. And the process of creating a subclass is often called "inheritance".

When the instances of class A find a method they don't know, they ask A. If A doesn't know about that method, it asks B!. That continues until no superclasses are left (nil is returned on that case).

This is very useful to organize the common functions into "groups and subgroups". This is not so easy to implement with regular non-oop tables and functions, and I'm not going to attempt it. For an example of inheritance, see the Person and AgedPerson example in the middleclass wiki.

The typical example: You could have a class called "Enemy" with one single method, called "damagePlayer", and then a subclass of Enemy called "Orc" that contained an orc-specific "Orc:draw()" method, and yet another subclass of Orc called MegaOrc that modified the damagePlayer method and increased the damage.

In middleclass, classes can only have 1 superclass, but they can have as many subclasses as needed. Every class generated has a superclass called Object, which provides some boilerplate methods. Object is the only class that doesn't have a superclass.

Finally, I'd also want to point out that the fact that classes and instances are tables on middleclass is just an implementation detail; other OOP implementations could use other stuff (for example Userdata). The important thing is not how OOP is implemented, but how it behaves.

Sorry for the long post. I hope it helps.