Question regarding metatables and OOP

Hi, i’ve followed some guides on how to implement OOP with metatables in my game. Everything was cool until I noticed I had to make all my own functions for corona functions like setFillColor and such (maybe i’m wrong here).

The thing is that when I tried to use a touch even listener, i was facing the same error, the image generated is not recognized as such.

This is a test project to explain what i’m trying to do:

--character.lua local character = {} local character\_mt = {\_\_index = character} function character.new(x,y,width,height,group) local image = display.newRect(x,y,width,height) local newCharacter = { image = image} image.anchorX = 0 image.anchorY = 0 if group then group:insert(image) end return setmetatable(newCharacter,character\_mt) end function character:setColor(r,g,b,a) self.image:setFillColor(r,g,b) a = a or 1 self.image.alpha = a end

--main.lua local character = require("character") --all ok, creates it and local myChar = character.new(400,200,100,100) myChar:setColor(0.5,1,1) --test function local function press(event) if event.phase == "ended" then print("pressed char") end end --doesnt work, myChar is nil myChar:addEventListener("touch",press)

So basically i would like to know how can I use an event listener in this case? And if it’s possible… how can I do to not have to create all the functions from scratch in my character.lua module (stuff like “image.alpha”, “image.isVisible”,etc,etc basically every property i dont wan’t to modify)?

Thanks!

Hi.

Basically, you just need to pull in the old __index and __newindex metamethods and stuff them into your new metatable, as-is or even with some of your own logic wrapped around them.

It’s kind of ugly (just circumventing a bug), but I’ve got an example here.

Hi StarCrunch, thanks for the answer.

I’m a little bit confused about this though, the event listener is called in my main.lua, the metatables are created in character.lua. You seem to have applied it into your “character” module, where the metatables are handled. How would I be able to do it in my example?

Sorry about it, kinda new to all this.

Thanks

Well, there are a couple ways you could do it.

In my “character”, I just applied it directly to the display object.

But assuming you want your code to remain mostly as is, I think you might want something like:

local character = {} local character\_mt -- forward reference -- I think--but am not 100% sure--that ordinary display objects share the -- same metatable; if you're paranoid, or actually encounter a contrary -- case, don't bother caching it, just make a new one each time. local function SetMetatable (instance) if not character\_mt then local object\_mt = getmetatable(instance.image) character\_mt = { \_\_index = function(t, k) local value = object\_mt.\_\_index(t.image, k) if value ~= nil then -- Property found in object? Note: checking against "nil" -- is important, versus "if not value", on account of -- boolean properties such as isVisible return value end -- Handle any other properties here. (Note: these are NOT fields you've added -- to your character instance. If those exist you won't even visit \_\_index.) if k == "mood" then return math.random() \< .5 and "happy" or "sad" end end, \_\_newindex = object\_mt.\_\_newindex } end return setmetatable(instance, character\_mt) end -- snip... return SetMetatable(newCharacter) -- in your character.new() function

So, basically, if your character instance doesn’t know what a property is, it will attempt lookup on the image. If something is found, it gets returned, and things should “just work”. The “other properties” just shows that you can make your own, if you’re so inclined.

Note that getting group:insert()group:remove(), display.remove(), etc. to respect this is probably more work than it’s worth. Also, be careful about comparing display objects accessed from a group, e.g. group[2] == MyCharacter. You could add an __eq metamethod to allow that, but I don’t know if that would violate any assumptions Corona is making. Here There Be Dragons.  :slight_smile:

Awsome, this is surely going to help me.

Thanks a lot for your help and time! 

Hi,

You might also look at https://github.com/Yonaba/30log if you don’t want to mess with all the meta table stuff.  I use it in almost every project, and it integrates perfectly with Corona SDK.

Cheers.

Hi, I remember someone using 30log and recommending it. It looked great and I even saved it for future use, but at one point I think I had so much good examples, modules and excellent material and I just… forget about it all. Then i remember this awsome module I saved one year ago and blame myself for trying to reinvent the wheel when there is a perfect working tool that someone thought it would help other developers and share it.

It has some really good potential for using in my current project but, currently, I can’t think of a way to implement an event listener like I want in my first example though. Could you please point me in the right direction?

Thanks a lot.

Hi,

My “dynamic-duo” - the two mods I use all the time are:

Classes/OOP - 30Log

Events: EventDispatcher

Simple and small stack with a lot of power.  I’ll write up a little example of how to make a class prototype that integrates the event functionality.

Hope that helps.  Cheers.

Hi.

Basically, you just need to pull in the old __index and __newindex metamethods and stuff them into your new metatable, as-is or even with some of your own logic wrapped around them.

It’s kind of ugly (just circumventing a bug), but I’ve got an example here.

Hi StarCrunch, thanks for the answer.

I’m a little bit confused about this though, the event listener is called in my main.lua, the metatables are created in character.lua. You seem to have applied it into your “character” module, where the metatables are handled. How would I be able to do it in my example?

Sorry about it, kinda new to all this.

Thanks

Well, there are a couple ways you could do it.

In my “character”, I just applied it directly to the display object.

But assuming you want your code to remain mostly as is, I think you might want something like:

local character = {} local character\_mt -- forward reference -- I think--but am not 100% sure--that ordinary display objects share the -- same metatable; if you're paranoid, or actually encounter a contrary -- case, don't bother caching it, just make a new one each time. local function SetMetatable (instance) if not character\_mt then local object\_mt = getmetatable(instance.image) character\_mt = { \_\_index = function(t, k) local value = object\_mt.\_\_index(t.image, k) if value ~= nil then -- Property found in object? Note: checking against "nil" -- is important, versus "if not value", on account of -- boolean properties such as isVisible return value end -- Handle any other properties here. (Note: these are NOT fields you've added -- to your character instance. If those exist you won't even visit \_\_index.) if k == "mood" then return math.random() \< .5 and "happy" or "sad" end end, \_\_newindex = object\_mt.\_\_newindex } end return setmetatable(instance, character\_mt) end -- snip... return SetMetatable(newCharacter) -- in your character.new() function

So, basically, if your character instance doesn’t know what a property is, it will attempt lookup on the image. If something is found, it gets returned, and things should “just work”. The “other properties” just shows that you can make your own, if you’re so inclined.

Note that getting group:insert()group:remove(), display.remove(), etc. to respect this is probably more work than it’s worth. Also, be careful about comparing display objects accessed from a group, e.g. group[2] == MyCharacter. You could add an __eq metamethod to allow that, but I don’t know if that would violate any assumptions Corona is making. Here There Be Dragons.  :slight_smile:

Awsome, this is surely going to help me.

Thanks a lot for your help and time! 

Hi,

You might also look at https://github.com/Yonaba/30log if you don’t want to mess with all the meta table stuff.  I use it in almost every project, and it integrates perfectly with Corona SDK.

Cheers.

Hi, I remember someone using 30log and recommending it. It looked great and I even saved it for future use, but at one point I think I had so much good examples, modules and excellent material and I just… forget about it all. Then i remember this awsome module I saved one year ago and blame myself for trying to reinvent the wheel when there is a perfect working tool that someone thought it would help other developers and share it.

It has some really good potential for using in my current project but, currently, I can’t think of a way to implement an event listener like I want in my first example though. Could you please point me in the right direction?

Thanks a lot.

Hi,

My “dynamic-duo” - the two mods I use all the time are:

Classes/OOP - 30Log

Events: EventDispatcher

Simple and small stack with a lot of power.  I’ll write up a little example of how to make a class prototype that integrates the event functionality.

Hope that helps.  Cheers.