Luoop - Lua oop library

Hello guys,

In my game project i have an extensive need for object oriented capabilities and all the existing libraries that i found for Lua were either too complicated to fiddle with them, or lacked some features that i needed, so in the end i crafted my own.
I shared it on github as an open-source project called Luoop, so just thought i would mention it in here just in case it can be of use to anyone :slight_smile:
Iā€™m still expanding the possibilities slowly and could definitely value some external feedback :slight_smile:

Here is the link:
https://github.com/TeddyEngel/Luoop

Cheers,
Teddy
[twitter]Teddy_Engel[/twitter]

@Teddy,

THANKS for the share! it is nice to see some OOP news. I wish Corona had implemented something like this. In any event, how would you use this library to deal with say visual objects (like images) and more importantly event listeners? Say I have a HUD in the game which shows #lives, points and so on. What about event like object collisions? I am using Storyboard and not sure really how to use this library for those basic game elements (display objects or event listeners)?Ā 

The example you show are good but I think people will probably need a more beefy example to apply. Of course just a suggestion:)

In any event, thank you again for sharing. I think we need a simple a Corona OOP infrastructure like Gideros and Moai SDKā€™s

Cheers,

MoĀ 

Hello Mo !

Thanks for your interest, itā€™s great indeed to hear some feedback :slight_smile:
A few things have been added to the library since i originally posted it, itā€™s highly iterative work since iā€™m basically adding to it when i encounter a case for which i need an additional development in my game project.

Your question is very very accurate actually, and in my personal case i have also recoded a whole director / event / listener implementation, as well as encapsulated the ā€˜nativeā€™ corona display objects into my own ones.
Main reasoning behind all this is that i wanted my events to work not only with physics / display objects, but basically anything and thatā€™s pretty much a requirement in the game iā€™m working on.
Same thing with display objects, i found out that it was probably cleaner to encapsulate native display objects so that i am
a ) secured against api changes (such as in the graphics 2.0 update) because i only need a few changes in my ā€˜facadeā€™ display layer
b ) able to craft easily reusable components. Basically i just wanted to be able to call almost new Clock() for example and create a clock object easily.

I think however that once iā€™m done with the current project iā€™ll share all the event side of the implementation since it can definitely be useful to other projects.

In your specific case, a display object that can handle native corona events try this:
Ā 

----------------------------------------------------------------------------------------- -- -- Control.lua -- ----------------------------------------------------------------------------------------- require (gsPathLuoop.."luoop") -- sClass system --- Constructor --- local function new(self, nX, nY, nWidth, nHeight, oReferencePoint) -- public members self.\_nX = nX self.\_nY = nY self.\_nWidth = nWidth self.\_nHeight = nHeight self.\_oReferencePoint = oReferencePoint -- private members self.\_sFamily = sFamily self.\_sId = sId self.\_oDisplayObject = nil end -- A class Control = class(new) --- Destructor --- function Control:destroy() self.\_nX = nil self.\_nY = nil self.\_nWidth = nil self.\_nHeight = nil self.\_oReferencePoint = nil self.\_oDisplayObject = nil end function Control:type() return 'Control' end -- Getters / setters function Control:\_getX() return self.\_nX end function Control:getX() return self:\_getX() end function Control:setX(nX) self.\_nX = nX -- Updating display object if needed local oDisplayObject = self:\_getDisplayObject() if oDisplayObject ~= nil then oDisplayObject.x = nX end end function Control:\_getY() return self.\_nY end function Control:getY() return self:\_getY() end function Control:setY(nY) self.\_nY = nY -- Updating display object if needed local oDisplayObject = self:\_getDisplayObject() if oDisplayObject ~= nil then oDisplayObject.y = nY end end function Control:\_getWidth() return self.\_nWidth end function Control:getWidth() return self:\_getWidth() end function Control:setWidth(nWidth) self.\_nWidth = nWidth -- Updating display object if needed local oDisplayObject = self:\_getDisplayObject() if oDisplayObject ~= nil then oDisplayObject.width = nWidth end end function Control:\_getHeight() return self.\_nHeight end function Control:getHeight() return self:\_getHeight() end function Control:setHeight(nHeight) self.\_nHeight = nHeight -- Updating display object if needed local oDisplayObject = self:\_getDisplayObject() if oDisplayObject ~= nil then oDisplayObject.height = nHeight end end function Control:getContentWidth() local nContentWidth = 0 local oDisplayObject = self:\_getDisplayObject() if oDisplayObject ~= nil then nContentWidth = oDisplayObject.contentWidth end return nContentWidth end function Control:getContentHeight() local nContentHeight = 0 local oDisplayObject = self:\_getDisplayObject() if oDisplayObject ~= nil then nContentHeight = oDisplayObject.contentHeight end return nContentHeight end function Control:\_getReferencePoint() return self.\_oReferencePoint end function Control:getReferencePoint() return self:\_getReferencePoint() end function Control:\_setReferencePoint(oReferencePoint) self.\_oReferencePoint = oReferencePoint end function Control:setReferencePoint(oReferencePoint) self:\_setReferencePoint(oReferencePoint) -- Updating display object if needed local oDisplayObject = self:\_getDisplayObject() if oDisplayObject ~= nil then oDisplayObject:setReferencePoint(oReferencePoint) end end function Control:\_getDisplayObject() return self.\_oDisplayObject end function Control:\_setDisplayObject(oDisplayObject) self.\_oDisplayObject = oDisplayObject end --- Methods --- function Control:refresh() -- Some controls require a specific routine to call when content is updated end function Control:render() -- Called when actually rendering by creating the display object and showing on screen end function Control:addOnTouchEvent(fctOnTouch) local oDisplayObject = self:\_getDisplayObject() return oDisplayObject:addEventListener( "touch", fctOnTouch) end function Control:removeOnTouchEvent(fctOnTouch) local oDisplayObject = self:\_getDisplayObject() return oDisplayObject:removeEventListener( "touch", fctOnTouch) end function Control:addOnTapEvent(fctOnTap) local oDisplayObject = self:\_getDisplayObject() return oDisplayObject:addEventListener( "tap", fctOnTap) end function Control:removeOnTapEvent(fctOnTap) local oDisplayObject = self:\_getDisplayObject() return oDisplayObject:removeEventListener( "tap", fctOnTap) end

Thatā€™s like a ā€˜genericā€™ control object from which you can create your inherited specific controls.
Once itā€™s created you just have to call yourControl:addOnTapEvent(yourHandler) to add an event listener on the object.
You could also call yourControl:addOnTapEvent(yourControl.fctInternalHandler) to keep the handler internal to the object :slight_smile:

The _methods are considered private methods, other public.

Feel free to contact me by pm / e-mail if you need more detail :slight_smile:

Edit: Added the example on the github repository.

@Teddy

Thanks so much for posting this!

Iā€™ve been relearning mobile programming in my (little) free time and had been debating if I wanted to use Corona because of its lack of a simple Object Oriented implementation. This looks like it does exactly what I was looking for! Iā€™m excited to start using this :slight_smile:

-Tyler

Thanks Teddy for the additional example and the extra info. I appreciate it. I have to admit that because I am new to OOP, it is going to take me sometime to absorb the info but I am very grateful that you took the time the answer and that you are willing to help. I will have a lot of questions!

Thanks.

Mo

@Tyler,
Haha i had the same ā€œissueā€, itā€™s really hard to go back to another paradigm once you are used to it :slight_smile:

@Mo,
I just updated the control example and also added a ā€˜labelā€™ class displaying a simple text so that you have a concrete example :slight_smile:
Note that itā€™s a basic example you will have to build upon it :wink: But that should give you an idea of how inheritance works with luoop, and how you can call a parent method (the label:render() automatically calls the control:render() method using _parentMethod()).

Enjoy !
Teddy

@engel.teddy Very cool.

@Mo This article might help for a better understanding of how the powerful and often simpler OOP pattern can work when building Corona apps.

Cheers.

@Teddy,

THANKS for the share! it is nice to see some OOP news. I wish Corona had implemented something like this. In any event, how would you use this library to deal with say visual objects (like images) and more importantly event listeners? Say I have a HUD in the game which shows #lives, points and so on. What about event like object collisions? I am using Storyboard and not sure really how to use this library for those basic game elements (display objects or event listeners)?Ā 

The example you show are good but I think people will probably need a more beefy example to apply. Of course just a suggestion:)

In any event, thank you again for sharing. I think we need a simple a Corona OOP infrastructure like Gideros and Moai SDKā€™s

Cheers,

MoĀ 

Hello Mo !

Thanks for your interest, itā€™s great indeed to hear some feedback :slight_smile:
A few things have been added to the library since i originally posted it, itā€™s highly iterative work since iā€™m basically adding to it when i encounter a case for which i need an additional development in my game project.

Your question is very very accurate actually, and in my personal case i have also recoded a whole director / event / listener implementation, as well as encapsulated the ā€˜nativeā€™ corona display objects into my own ones.
Main reasoning behind all this is that i wanted my events to work not only with physics / display objects, but basically anything and thatā€™s pretty much a requirement in the game iā€™m working on.
Same thing with display objects, i found out that it was probably cleaner to encapsulate native display objects so that i am
a ) secured against api changes (such as in the graphics 2.0 update) because i only need a few changes in my ā€˜facadeā€™ display layer
b ) able to craft easily reusable components. Basically i just wanted to be able to call almost new Clock() for example and create a clock object easily.

I think however that once iā€™m done with the current project iā€™ll share all the event side of the implementation since it can definitely be useful to other projects.

In your specific case, a display object that can handle native corona events try this:
Ā 

----------------------------------------------------------------------------------------- -- -- Control.lua -- ----------------------------------------------------------------------------------------- require (gsPathLuoop.."luoop") -- sClass system --- Constructor --- local function new(self, nX, nY, nWidth, nHeight, oReferencePoint) -- public members self.\_nX = nX self.\_nY = nY self.\_nWidth = nWidth self.\_nHeight = nHeight self.\_oReferencePoint = oReferencePoint -- private members self.\_sFamily = sFamily self.\_sId = sId self.\_oDisplayObject = nil end -- A class Control = class(new) --- Destructor --- function Control:destroy() self.\_nX = nil self.\_nY = nil self.\_nWidth = nil self.\_nHeight = nil self.\_oReferencePoint = nil self.\_oDisplayObject = nil end function Control:type() return 'Control' end -- Getters / setters function Control:\_getX() return self.\_nX end function Control:getX() return self:\_getX() end function Control:setX(nX) self.\_nX = nX -- Updating display object if needed local oDisplayObject = self:\_getDisplayObject() if oDisplayObject ~= nil then oDisplayObject.x = nX end end function Control:\_getY() return self.\_nY end function Control:getY() return self:\_getY() end function Control:setY(nY) self.\_nY = nY -- Updating display object if needed local oDisplayObject = self:\_getDisplayObject() if oDisplayObject ~= nil then oDisplayObject.y = nY end end function Control:\_getWidth() return self.\_nWidth end function Control:getWidth() return self:\_getWidth() end function Control:setWidth(nWidth) self.\_nWidth = nWidth -- Updating display object if needed local oDisplayObject = self:\_getDisplayObject() if oDisplayObject ~= nil then oDisplayObject.width = nWidth end end function Control:\_getHeight() return self.\_nHeight end function Control:getHeight() return self:\_getHeight() end function Control:setHeight(nHeight) self.\_nHeight = nHeight -- Updating display object if needed local oDisplayObject = self:\_getDisplayObject() if oDisplayObject ~= nil then oDisplayObject.height = nHeight end end function Control:getContentWidth() local nContentWidth = 0 local oDisplayObject = self:\_getDisplayObject() if oDisplayObject ~= nil then nContentWidth = oDisplayObject.contentWidth end return nContentWidth end function Control:getContentHeight() local nContentHeight = 0 local oDisplayObject = self:\_getDisplayObject() if oDisplayObject ~= nil then nContentHeight = oDisplayObject.contentHeight end return nContentHeight end function Control:\_getReferencePoint() return self.\_oReferencePoint end function Control:getReferencePoint() return self:\_getReferencePoint() end function Control:\_setReferencePoint(oReferencePoint) self.\_oReferencePoint = oReferencePoint end function Control:setReferencePoint(oReferencePoint) self:\_setReferencePoint(oReferencePoint) -- Updating display object if needed local oDisplayObject = self:\_getDisplayObject() if oDisplayObject ~= nil then oDisplayObject:setReferencePoint(oReferencePoint) end end function Control:\_getDisplayObject() return self.\_oDisplayObject end function Control:\_setDisplayObject(oDisplayObject) self.\_oDisplayObject = oDisplayObject end --- Methods --- function Control:refresh() -- Some controls require a specific routine to call when content is updated end function Control:render() -- Called when actually rendering by creating the display object and showing on screen end function Control:addOnTouchEvent(fctOnTouch) local oDisplayObject = self:\_getDisplayObject() return oDisplayObject:addEventListener( "touch", fctOnTouch) end function Control:removeOnTouchEvent(fctOnTouch) local oDisplayObject = self:\_getDisplayObject() return oDisplayObject:removeEventListener( "touch", fctOnTouch) end function Control:addOnTapEvent(fctOnTap) local oDisplayObject = self:\_getDisplayObject() return oDisplayObject:addEventListener( "tap", fctOnTap) end function Control:removeOnTapEvent(fctOnTap) local oDisplayObject = self:\_getDisplayObject() return oDisplayObject:removeEventListener( "tap", fctOnTap) end

Thatā€™s like a ā€˜genericā€™ control object from which you can create your inherited specific controls.
Once itā€™s created you just have to call yourControl:addOnTapEvent(yourHandler) to add an event listener on the object.
You could also call yourControl:addOnTapEvent(yourControl.fctInternalHandler) to keep the handler internal to the object :slight_smile:

The _methods are considered private methods, other public.

Feel free to contact me by pm / e-mail if you need more detail :slight_smile:

Edit: Added the example on the github repository.

@Teddy

Thanks so much for posting this!

Iā€™ve been relearning mobile programming in my (little) free time and had been debating if I wanted to use Corona because of its lack of a simple Object Oriented implementation. This looks like it does exactly what I was looking for! Iā€™m excited to start using this :slight_smile:

-Tyler

Thanks Teddy for the additional example and the extra info. I appreciate it. I have to admit that because I am new to OOP, it is going to take me sometime to absorb the info but I am very grateful that you took the time the answer and that you are willing to help. I will have a lot of questions!

Thanks.

Mo

@Tyler,
Haha i had the same ā€œissueā€, itā€™s really hard to go back to another paradigm once you are used to it :slight_smile:

@Mo,
I just updated the control example and also added a ā€˜labelā€™ class displaying a simple text so that you have a concrete example :slight_smile:
Note that itā€™s a basic example you will have to build upon it :wink: But that should give you an idea of how inheritance works with luoop, and how you can call a parent method (the label:render() automatically calls the control:render() method using _parentMethod()).

Enjoy !
Teddy

@engel.teddy Very cool.

@Mo This article might help for a better understanding of how the powerful and often simpler OOP pattern can work when building Corona apps.

Cheers.

A few updates:
Since the creation, I expanded the library and added singleton support as well as parent class method calling.

Added today new clearer examples for each possible case.

I also removed the deprecated corona control examples since they werenā€™t really relevant anymore :slight_smile:

Cheers,
Teddy

Thanks a lot Mr Teddy! - looking forward to using your library.Ā 

A few updates:
Since the creation, I expanded the library and added singleton support as well as parent class method calling.

Added today new clearer examples for each possible case.

I also removed the deprecated corona control examples since they werenā€™t really relevant anymore :slight_smile:

Cheers,
Teddy

Thanks a lot Mr Teddy! - looking forward to using your library.Ā 

How would you go about inserting these child objects into a display group?Ā 

Thatā€™s the main limitation of objects you create that way.
The corona display group system will definitely ā€œnotā€ call your object destroy function to make sure memory is freed, and you cannot ā€œinsertā€ them as such since they arenā€™t corona display objects.

In this case, itā€™s better to consider the luoop view object as a wrapper around a corona display group.
You could hijack the removeSelf function to make it call the destructor automatically but you would still have the issue when there is a hierarchy of corona display groups / objects - parent groups seem to call an internal display cleanup function different to removeSelf()

Conclusion is: Either use a whole luoop stack and wrap your groups inside them, or use luoop for the model / controller objects only if it is an issue

Ā 

Iā€™ve my own entirely different system which has destructors (non automatic obviously) and I think the latter is the solution. Objects are used for game scenes, some abstract display objects, resources etc. but the actual Corona flat implementation of objects displays as is.Ā 

Objects that need their displays manipulated (e.g. game scenes so the game manager can do state changes fade in/out etc.) have a getDisplayObject() method.

Banjaxing around with Corona SDK is generally not a good idea - I donā€™t even recommend basic decoration because Corona could add methods to the API.Ā 

I think it introduces unnecessary complexity anyway.Ā 

In my system if you have an object that (say) represents a score display the actual implementation is hidden in the object, built up by the constructor and torn down by the destructor. It allows some automation - the object can be added to the scene in such a way that when the scene is destroyed its child objects are too, but the actual Corona tear-down is still done the same old fashioned way.