OOP modules help needed

Hi there folks!

I need some help with OOP-like modules using metatables - I’m quite good at all Corona programming, but OOP seems to be a big hurdle for me. I’ve read all tutorials but I keep on making errors, so would you guys and girls like at my code for a second? Thanks!

What I want to do in a nutshell is this:

  1. Create bullets that have their own move-and-die logic, as instances of a bullet class.
  2. Retain control over the bullets from my main.lua script, so I can kill all bullets when this is needed (etc. on gameover).

So, here’s my main.lua code:

local bullet = require("bullet")  
  
bulletList = {}  
  
local function createBullet()  
 bulletList[#bulletList+1] = bullet.new(200,200,math.random(360),5)  
end  
  
timer.performWithDelay(200, createBullet, 0)  
  
local function killBullet()  
  
 if math.random(25) == 5 then  
 -- delete bullet  
 for i = #bulletList, 1, -1 do  
 bulletList[i].destroy()  
 bulletList.remove(i)  
 end  
 end  
end  
  
Runtime:addEventListener("enterFrame", killBullet)  

and here is my bullet.lua module:

-- bullet.lua --  
----------------  
  
local bullet = {}  
local bullet\_mt = { \_\_index = bullet} -- metatable  
  
-- private functions  
  
-- public functions  
function bullet.new(startX, startY, angle, speed)  
  
 -- forward references  
 local moveBullet  
  
 local newBullet = {}  
 newBullet.image = display.newImage("bullet.png")  
 newBullet.image.x = startX  
 newBullet.image.y = startY  
 newBullet.image.rotation = angle  
 newBullet.image.xScale = .1  
 newBullet.image.yScale = .1  
 transition.to(newBullet.image, {time = 200, xScale = 1, yScale = 1})  
  
 function newBullet.destroy()  
 Runtime:removeEventListener("enterFrame", moveBullet)  
 newBullet.image:removeSelf()  
 newBullet = nil  
 end  
  
 moveBullet = function()  
 newBullet.image.x = newBullet.image.x + math.cos(math.rad(angle))\*speed  
 newBullet.image.y = newBullet.image.y + math.sin(math.rad(angle))\*speed  
 if newBullet.image.x \> 500 then  
 newBullet.destroy()  
 end  
 end  
  
 Runtime:addEventListener("enterFrame", moveBullet)  
  
 return setmetatable (newBullet, bullet\_mt)   
end  
  
return bullet  

Jon Beebes tutorials make some sense, but I quickly get lost when it come to knowing where to put my functions, using self etc…

Any help is greatly appreciated!

Thanks,
Thomas [import]uid: 70134 topic_id: 34539 reply_id: 334539[/import]

Start by moving bullet member functions out of your new section.

example:

function newBullet:destroy()  
 Runtime:removeEventListener("enterFrame", moveBullet)  
 newBullet.image:removeSelf()  
 newBullet = nil  
end  

becomes

function newBullet:destroy ()  
 Runtime:removeEventListener("enterFrame", self.moveBullet) --this needs to bind to itself too  
 self.image:removeSelf()  
 self = nil -- not sure if this part will work...  
end  

So the bullet can reference and destroy itself.

Thats only the first part of the problem, and you’re going to start running into nil tree errors with what you have written rather quickly. I really recommend you check out ardentkid’s OO tutorials, they’re a little more specific to the problem you’re trying to solve actually. This one for instance is an example of almost exactly what you’re trying to do only using “Enemies” instead of bullets:
http://www.ardentkid.com/blog/2012-11-27/non-static-classes-func-inheritance-oo-lua-24

Hope this helps, I spent about 4 hours last night trying to understand all of this, and a background in JavaScript oddly helped a lot. [import]uid: 130806 topic_id: 34539 reply_id: 137344[/import]

Hi Chris!

This looks like an excellent start, although I’m puzzled by the lack of metatables. I though metatables were a precondition to correct memory usage - oh well, we’ll see how far we get!

Thanks,
Thomas [import]uid: 70134 topic_id: 34539 reply_id: 137355[/import]

AFAIK metatables are really only there to facilitate a form of inheritance. [import]uid: 33275 topic_id: 34539 reply_id: 137357[/import]

Hey Segaboy,

Like I said I’m no genius when it comes to these things, but I thought that metatables allows you to sort say “if you don’t find a given function in this object, then look towards the parent object for a function with the same name”. This allows you to create 100 bullets onscreen without a moveBullet() function, because you can call it in the one “parent-object” (for lack of a better name). Without metatables each of your bullets has its own separate moveBullet() function, which obviously is bad for memory.

Well, at least that’s the impression that I get, and the reason why I think I’d like to find a way to do my OOP using metatables.

Cheers,
Thomas [import]uid: 70134 topic_id: 34539 reply_id: 137359[/import]

You’ve got it exactly right - you’ve just described inheritance brilliantly :slight_smile:

If you check out Omid’s blog listed above, in his last post on the subject you’ll find him detailing inheritance and using metatables for this purpose.

It’s something that fascinates me but beyond the initial concept I get horribly lost during the actual implementation. Omid’s explanations are the best I’ve seen on the subject so I thoroughly recommend giving them a read. Hopefully when he gets some spare time he’s going to rework the blog posts into a fully-fledged, working code tutorial on the subject that should appear on the Corona Labs blog at some point. [import]uid: 33275 topic_id: 34539 reply_id: 137362[/import]

Little more info - read up about __index and __newindex on PiL - I found that really helpful when it came to understanding exactly what metatables do. [import]uid: 33275 topic_id: 34539 reply_id: 137363[/import]

Hey Segaboy,

Yes, that’s a good read - I already knew that one, and it also helped me to understand metatables greatly. It makes inheritance a really simple practical concept to grasp. Unfortunately the problems come when I need to code, and I don’t see where and why to put dots or colons, use self or newBullet (the instance) or Bullet (the class)…

In theory I do get all of this: you define a table called Bullet, and then define a command that creates new tables, and attaches the metatable of the class Bullet. In practice things go wrong and I’m lost in a jungle of scope, upvalues, nils etcetera. Will try out some more things tonight!

Cheers,
Thomas [import]uid: 70134 topic_id: 34539 reply_id: 137377[/import]

Same here - it doesn’t help that Lua’s flexibility allows for a myriad of ways to implement OOP design. I wish Corona would adopt an ‘endorsed’ way of doing this, hoping that Omid’s planned tutorial might kickstart that.

Remember the colon passes the instance automatically, so these two are the syntactically the same:

bullet:shoot(x,y)
bullet.shoot(self,x,y)

Self is the instance of bullet that has been created from the Bullet.new() class.

As I said before I’m in the same boat, understand the concepts and at pen-paper stage, but as soon as I get into code it all begins to unravel. [import]uid: 33275 topic_id: 34539 reply_id: 137378[/import]

Start by moving bullet member functions out of your new section.

example:

function newBullet:destroy()  
 Runtime:removeEventListener("enterFrame", moveBullet)  
 newBullet.image:removeSelf()  
 newBullet = nil  
end  

becomes

function newBullet:destroy ()  
 Runtime:removeEventListener("enterFrame", self.moveBullet) --this needs to bind to itself too  
 self.image:removeSelf()  
 self = nil -- not sure if this part will work...  
end  

So the bullet can reference and destroy itself.

Thats only the first part of the problem, and you’re going to start running into nil tree errors with what you have written rather quickly. I really recommend you check out ardentkid’s OO tutorials, they’re a little more specific to the problem you’re trying to solve actually. This one for instance is an example of almost exactly what you’re trying to do only using “Enemies” instead of bullets:
http://www.ardentkid.com/blog/2012-11-27/non-static-classes-func-inheritance-oo-lua-24

Hope this helps, I spent about 4 hours last night trying to understand all of this, and a background in JavaScript oddly helped a lot. [import]uid: 130806 topic_id: 34539 reply_id: 137344[/import]

Hi Chris!

This looks like an excellent start, although I’m puzzled by the lack of metatables. I though metatables were a precondition to correct memory usage - oh well, we’ll see how far we get!

Thanks,
Thomas [import]uid: 70134 topic_id: 34539 reply_id: 137355[/import]

AFAIK metatables are really only there to facilitate a form of inheritance. [import]uid: 33275 topic_id: 34539 reply_id: 137357[/import]

Hey Segaboy,

Like I said I’m no genius when it comes to these things, but I thought that metatables allows you to sort say “if you don’t find a given function in this object, then look towards the parent object for a function with the same name”. This allows you to create 100 bullets onscreen without a moveBullet() function, because you can call it in the one “parent-object” (for lack of a better name). Without metatables each of your bullets has its own separate moveBullet() function, which obviously is bad for memory.

Well, at least that’s the impression that I get, and the reason why I think I’d like to find a way to do my OOP using metatables.

Cheers,
Thomas [import]uid: 70134 topic_id: 34539 reply_id: 137359[/import]

You’ve got it exactly right - you’ve just described inheritance brilliantly :slight_smile:

If you check out Omid’s blog listed above, in his last post on the subject you’ll find him detailing inheritance and using metatables for this purpose.

It’s something that fascinates me but beyond the initial concept I get horribly lost during the actual implementation. Omid’s explanations are the best I’ve seen on the subject so I thoroughly recommend giving them a read. Hopefully when he gets some spare time he’s going to rework the blog posts into a fully-fledged, working code tutorial on the subject that should appear on the Corona Labs blog at some point. [import]uid: 33275 topic_id: 34539 reply_id: 137362[/import]

Little more info - read up about __index and __newindex on PiL - I found that really helpful when it came to understanding exactly what metatables do. [import]uid: 33275 topic_id: 34539 reply_id: 137363[/import]

Hey Segaboy,

Yes, that’s a good read - I already knew that one, and it also helped me to understand metatables greatly. It makes inheritance a really simple practical concept to grasp. Unfortunately the problems come when I need to code, and I don’t see where and why to put dots or colons, use self or newBullet (the instance) or Bullet (the class)…

In theory I do get all of this: you define a table called Bullet, and then define a command that creates new tables, and attaches the metatable of the class Bullet. In practice things go wrong and I’m lost in a jungle of scope, upvalues, nils etcetera. Will try out some more things tonight!

Cheers,
Thomas [import]uid: 70134 topic_id: 34539 reply_id: 137377[/import]

Same here - it doesn’t help that Lua’s flexibility allows for a myriad of ways to implement OOP design. I wish Corona would adopt an ‘endorsed’ way of doing this, hoping that Omid’s planned tutorial might kickstart that.

Remember the colon passes the instance automatically, so these two are the syntactically the same:

bullet:shoot(x,y)
bullet.shoot(self,x,y)

Self is the instance of bullet that has been created from the Bullet.new() class.

As I said before I’m in the same boat, understand the concepts and at pen-paper stage, but as soon as I get into code it all begins to unravel. [import]uid: 33275 topic_id: 34539 reply_id: 137378[/import]

chris-allnut - When you do “self=nil” in your example, you’re not actually setting the ‘newbullet’ to nil. As SegaBoy mentioned, table functions run the same as anonymous functions that are passed “self” for the first argument – “self” is automatically declared locally (as reference to the function’s parent table), when the table function runs. However, ownership can be re-assigned through dot notation (also known as “decorating”/ “inheritance”). That’s why I leave creation and destruction of instances up to the Class, not the (instances themselves).

thomas6 - Try to define functions with colon notation when you feel that an object should own the function (i.e. when something needs to move, jump, etc). and define functions with dot notation if they need to be assigned late, locally (temporary), to change ownership (decorate/ inherit), or when ownership is clearly not needed.

Thanks for all the good words, it totally make writing the tutorials worth while! [import]uid: 36792 topic_id: 34539 reply_id: 138004[/import]

ArdentKid,
I thought that

function object.setNil(self, a, b)  
 self = nil  
end  

was the same as

function object:setNil(a, b)   
 self = nil  
end  

but your saying the first just passes a reference, while the seconds self is the actual object?

Or is it a difference of a table function vs a locally defined function used with a closure? [import]uid: 130806 topic_id: 34539 reply_id: 138011[/import]

chris-allnutt - Correct, the functions are essentially the same, but the issue has to do with scoping. When passing variables, they are always received locally. By nil-ing “self”, you are only nil-ing the local reference. However, since “self” is also being referenced outside of your function (it exists elsewhere), then any other modifications you make to that reference will sustain.

Just remember always have to nil from the parent level, which is why it’s best to have the Class do it for an instance such as a bullet. [import]uid: 36792 topic_id: 34539 reply_id: 138016[/import]