Object-Oriented Lua Tutorials

I wrote a 4-part tutorial on how to structure your game code in an OO fashion. I’ve gotten highly positive reviews from it as well. Hope it helps!

I. Introduction and Setup

II. Classes (Encapsulation)

III. Custom Events

IV. Inheritance and Polymorphism

V. Working Example

Please feel free to leave your feedback here!

These tutorials are great!

Thank you [import]uid: 101952 topic_id: 33679 reply_id: 133919[/import]

WOW! Fantastic tutorial! I am going to start my next app the right way this time using your approach. I have 2 questions:

1- what about say something like collisions between object? For instance I want an object to change color when it collide with another object (of different class like cat and mouse using your code example) do I need to keep the collision code seperate from the class cat and dog or integrate them into the cat/mouse classes like you did with show hide functions?

2- I would love to see a small app example combining all the concepts in your tutorial. It is one thing to see each bloc but it would really if we could see for instance a typical main.lua and maybe couple of modules representing the different behaviors. You could even use the cat and mouse modules!

Thanks for sharing a much better way to program in Lua/Corona. Lua is great but as soon the app gets complex, it really a nightmare to keep track of everything! Your way is a great solution.

THANKS.

Mo
@Lairdgames [import]uid: 100814 topic_id: 33679 reply_id: 134045[/import]

Thanks Guys!

LaridGames-
1- The best practice I know for manual collision detection is to keep it separate from the rest of your game (in a class called Collision.lua). Using the cat and mouse example, I would dispatch an event to add collision when showing an object, and then remove it when hiding. So when the cat/ mouse shows itself, do

scene:dispatchEvent({name='addCollision', target=self})  

Do something similar for when they hide off-screen (i.e. ‘removeCollision’)

Then have the Collision class listen for the add and remove events starting when the class loads:

scene:addEventListener('addCollision', Collision)  
function Collision:addCollision(event)  
 --add event.target to an array. i.e. self.catArr or self.mouseArr  
 --based on a property like event.target.name  
end  

The Collision class should also always be running a Runtime check on the arrays you want to compare collision. If you’re checking everything against everything, then you can probably just have one array.

When something collides, dispatch an ‘onCollision’ event with both targets as parameters (you can do “target1”, “target2” or “target” and “other”, whatever)

2- Wish I had the time to provide sample code. I may be able to hack something up in the coming weeks, heard the same request for the dynamic sprites tutorials. The only thing I really have in my main.lua (except for global variables and device checking) is storyboard.gotoScene(“SceneTitle”). [import]uid: 36792 topic_id: 33679 reply_id: 134048[/import]

Thank you! That’s great stuff. Would love to see a collision class define in your tutorial serie when you get a chance. No problem about a full sample. I was just curious about how to setup the app since I am use to basically put everything into a gameScreen.lua module. Your way seems 1000 ways better!
It seems if I understand correctly, for any app you would simply:

1- create a class for each object (cat or mouse) or for each game element like score, health bar
2- let those objects/elements talk to each other and react in appropriate manner

That’s sound easier than controlling everything with spaghetti code all in one module !

THANKS!

Mo
[import]uid: 100814 topic_id: 33679 reply_id: 134089[/import]

Yup, that’s the power of Object Oriented :slight_smile: [import]uid: 36792 topic_id: 33679 reply_id: 134099[/import]

These tutorials are great!

Thank you [import]uid: 101952 topic_id: 33679 reply_id: 133919[/import]

WOW! Fantastic tutorial! I am going to start my next app the right way this time using your approach. I have 2 questions:

1- what about say something like collisions between object? For instance I want an object to change color when it collide with another object (of different class like cat and mouse using your code example) do I need to keep the collision code seperate from the class cat and dog or integrate them into the cat/mouse classes like you did with show hide functions?

2- I would love to see a small app example combining all the concepts in your tutorial. It is one thing to see each bloc but it would really if we could see for instance a typical main.lua and maybe couple of modules representing the different behaviors. You could even use the cat and mouse modules!

Thanks for sharing a much better way to program in Lua/Corona. Lua is great but as soon the app gets complex, it really a nightmare to keep track of everything! Your way is a great solution.

THANKS.

Mo
@Lairdgames [import]uid: 100814 topic_id: 33679 reply_id: 134045[/import]

Thanks Guys!

LaridGames-
1- The best practice I know for manual collision detection is to keep it separate from the rest of your game (in a class called Collision.lua). Using the cat and mouse example, I would dispatch an event to add collision when showing an object, and then remove it when hiding. So when the cat/ mouse shows itself, do

scene:dispatchEvent({name='addCollision', target=self})  

Do something similar for when they hide off-screen (i.e. ‘removeCollision’)

Then have the Collision class listen for the add and remove events starting when the class loads:

scene:addEventListener('addCollision', Collision)  
function Collision:addCollision(event)  
 --add event.target to an array. i.e. self.catArr or self.mouseArr  
 --based on a property like event.target.name  
end  

The Collision class should also always be running a Runtime check on the arrays you want to compare collision. If you’re checking everything against everything, then you can probably just have one array.

When something collides, dispatch an ‘onCollision’ event with both targets as parameters (you can do “target1”, “target2” or “target” and “other”, whatever)

2- Wish I had the time to provide sample code. I may be able to hack something up in the coming weeks, heard the same request for the dynamic sprites tutorials. The only thing I really have in my main.lua (except for global variables and device checking) is storyboard.gotoScene(“SceneTitle”). [import]uid: 36792 topic_id: 33679 reply_id: 134048[/import]

Thank you! That’s great stuff. Would love to see a collision class define in your tutorial serie when you get a chance. No problem about a full sample. I was just curious about how to setup the app since I am use to basically put everything into a gameScreen.lua module. Your way seems 1000 ways better!
It seems if I understand correctly, for any app you would simply:

1- create a class for each object (cat or mouse) or for each game element like score, health bar
2- let those objects/elements talk to each other and react in appropriate manner

That’s sound easier than controlling everything with spaghetti code all in one module !

THANKS!

Mo
[import]uid: 100814 topic_id: 33679 reply_id: 134089[/import]

Yup, that’s the power of Object Oriented :slight_smile: [import]uid: 36792 topic_id: 33679 reply_id: 134099[/import]

Hello ArdentKid,

I find these tutorials helpful in reinforcing what I was already applying on my own application. But I was wondering about one particular aspect that I am not too sure about.

How do you access class properties from an instance function?

For example, say your Enemy class had a class property maxAttacks to define the maximum number of attacks the enemy can do. This should apply to all enemies, hence why it makes sense to make it a class property.

Now, each enemy instance has the attack() function where part of it would check if that maximum has been reached, but within that attack function, ‘self’ refers to the enemy instance not the Enemy class.

Now, upon creating each enemy instance I could copy the value of that class property to a property in the instance thus making it available through ‘self’ in the attack function. But since it is going to be the same for every instance, it seems wasteful to do that.

Thanks for your help. [import]uid: 142439 topic_id: 33679 reply_id: 134739[/import]

Hey rcuba87 - You can reference those “static class variables” by just using the class name! For example:

--Enemy.lua  
local Enemy = {  
 MaxAttacks = 10  
}  
  
function Enemy:New()  
 --blah blah  
end  
  
function Enemy:attack()  
 if (self.totalAttacks == Enemy.MaxAttacks) then  
 --do stuff  
 end  
end  

As a matter of fact, anything defined “locally” outside of the class functions, but in the same file (including the Class itself) are available to all the functions in that file. Hope that helps! [import]uid: 36792 topic_id: 33679 reply_id: 134743[/import]

Hey ArdentKid,

Thanks for the reply, definitely helped. I don’t know why I didn’t just try that at first. I’m sorry to bother you again, but I have another question regarding an OO approach in LUA. Sorry if it is a bit long, but I would really appreciate your opinion.

How would you handle Subclassing/Inheritance in your implementation (specially regarding the Instances recycling)?

To keep with the running example (even though I don’t have ‘enemies’ in my app haha), One could keep the single ‘Enemy’ class and create some logic to differentiate between types of instances and create or re-use the specific instances (i.e. with the specific image/sprites and specific properties/values) when necessary, but it makes more sense to make them into their own subclasses.

My issue is exactly how to handle the inheritance while maintaining the idea of the instance recycling.

Here is how I see it. Please let me know what you think.

First the parent Enemy class. It only defines and prepares an instance and attaches any properties and functions that every Enemy type should have. It does not keep track of instances. This is up to the subclasses

[lua]–Enemy.lua

local Enemy = {
– All class properties Enemy
}

function Enemy:New(config)
– Create new Image/Sprite using parameters included in ‘config’
– Attach all instance level properties that all enemy objects should have with values from ‘config’
– Attach all instance level functions that all enemy objects should have
– Return the instance
end

– All other function definitions (like the instance functions) for this parent class

return Enemy[/lua]

Now the subclass. This uses the parent class to create a basic instance, attaches all properties/functions specific to the sublcass instances and also keeps track of its own instances for recycling.
[lua]–SubEnemy.lua

local Enemy = EnemyClass – EnemyClass = require( “Enemy” ) has already been called on whatever script will include this Enemy sublcass

local SubEnemy = {
– All class properties for Subenemy
Instances = {},
defaultConfig = nil – This would be the default values of all properties (including Image/Sprite info) for all instances of this class
}

–This function would be called right after loading the script with a table of all the default values to be used when generating new instances
function SubEnemy:Initialize(config)
defaultConfig = config
end

function SubEnemy:New(config)

local seInstance = Enemy:New(config) – The ‘config’ used would be either the parameter to this function or, if that is nil, then the ‘defaultConfig’ of the class

– Attach all instance level properties of subEnemy objects with values from ‘config’, if ‘config’ is nil, use class defaultConfig
– Attach all instance level functions subEnemy objects
– Override any property/function necessary by just re-defining and re-assigning

table.insert(self.Instances, seInstance)

return seInstance
end

function SubEnemy:Get(config)
– Check for available instance, if so, reset using ‘config’, if ‘config’ is nil, use class defaultConfig
– If no instance is available, create a new one (passing ‘config’)
– return the new instance
end

function SubEnemy:Dispose(obj)
– As your implementation
end

– All other function definitions (like the instance functions) for this parent class

return SubEnemy[/lua] [import]uid: 142439 topic_id: 33679 reply_id: 135010[/import]

Hello ArdentKid,

I find these tutorials helpful in reinforcing what I was already applying on my own application. But I was wondering about one particular aspect that I am not too sure about.

How do you access class properties from an instance function?

For example, say your Enemy class had a class property maxAttacks to define the maximum number of attacks the enemy can do. This should apply to all enemies, hence why it makes sense to make it a class property.

Now, each enemy instance has the attack() function where part of it would check if that maximum has been reached, but within that attack function, ‘self’ refers to the enemy instance not the Enemy class.

Now, upon creating each enemy instance I could copy the value of that class property to a property in the instance thus making it available through ‘self’ in the attack function. But since it is going to be the same for every instance, it seems wasteful to do that.

Thanks for your help. [import]uid: 142439 topic_id: 33679 reply_id: 134739[/import]

Hey rcuba87 - You can reference those “static class variables” by just using the class name! For example:

--Enemy.lua  
local Enemy = {  
 MaxAttacks = 10  
}  
  
function Enemy:New()  
 --blah blah  
end  
  
function Enemy:attack()  
 if (self.totalAttacks == Enemy.MaxAttacks) then  
 --do stuff  
 end  
end  

As a matter of fact, anything defined “locally” outside of the class functions, but in the same file (including the Class itself) are available to all the functions in that file. Hope that helps! [import]uid: 36792 topic_id: 33679 reply_id: 134743[/import]

Hey ArdentKid,

Thanks for the reply, definitely helped. I don’t know why I didn’t just try that at first. I’m sorry to bother you again, but I have another question regarding an OO approach in LUA. Sorry if it is a bit long, but I would really appreciate your opinion.

How would you handle Subclassing/Inheritance in your implementation (specially regarding the Instances recycling)?

To keep with the running example (even though I don’t have ‘enemies’ in my app haha), One could keep the single ‘Enemy’ class and create some logic to differentiate between types of instances and create or re-use the specific instances (i.e. with the specific image/sprites and specific properties/values) when necessary, but it makes more sense to make them into their own subclasses.

My issue is exactly how to handle the inheritance while maintaining the idea of the instance recycling.

Here is how I see it. Please let me know what you think.

First the parent Enemy class. It only defines and prepares an instance and attaches any properties and functions that every Enemy type should have. It does not keep track of instances. This is up to the subclasses

[lua]–Enemy.lua

local Enemy = {
– All class properties Enemy
}

function Enemy:New(config)
– Create new Image/Sprite using parameters included in ‘config’
– Attach all instance level properties that all enemy objects should have with values from ‘config’
– Attach all instance level functions that all enemy objects should have
– Return the instance
end

– All other function definitions (like the instance functions) for this parent class

return Enemy[/lua]

Now the subclass. This uses the parent class to create a basic instance, attaches all properties/functions specific to the sublcass instances and also keeps track of its own instances for recycling.
[lua]–SubEnemy.lua

local Enemy = EnemyClass – EnemyClass = require( “Enemy” ) has already been called on whatever script will include this Enemy sublcass

local SubEnemy = {
– All class properties for Subenemy
Instances = {},
defaultConfig = nil – This would be the default values of all properties (including Image/Sprite info) for all instances of this class
}

–This function would be called right after loading the script with a table of all the default values to be used when generating new instances
function SubEnemy:Initialize(config)
defaultConfig = config
end

function SubEnemy:New(config)

local seInstance = Enemy:New(config) – The ‘config’ used would be either the parameter to this function or, if that is nil, then the ‘defaultConfig’ of the class

– Attach all instance level properties of subEnemy objects with values from ‘config’, if ‘config’ is nil, use class defaultConfig
– Attach all instance level functions subEnemy objects
– Override any property/function necessary by just re-defining and re-assigning

table.insert(self.Instances, seInstance)

return seInstance
end

function SubEnemy:Get(config)
– Check for available instance, if so, reset using ‘config’, if ‘config’ is nil, use class defaultConfig
– If no instance is available, create a new one (passing ‘config’)
– return the new instance
end

function SubEnemy:Dispose(obj)
– As your implementation
end

– All other function definitions (like the instance functions) for this parent class

return SubEnemy[/lua] [import]uid: 142439 topic_id: 33679 reply_id: 135010[/import]

Hey rcuba87 - sorry for the late reply!

To answer your question, I only keep track of instances in my Final Classes. Also, I’ve finished the inheritance tutorial, hope it helps:

http://www.ardentkid.com/blog/2012-12-24/inheritance-oo-lua-44 [import]uid: 36792 topic_id: 33679 reply_id: 136295[/import]

Thanks for sharing these tutorials with everyone! [import]uid: 84637 topic_id: 33679 reply_id: 136298[/import]

Hey rcuba87 - sorry for the late reply!

To answer your question, I only keep track of instances in my Final Classes. Also, I’ve finished the inheritance tutorial, hope it helps:

http://www.ardentkid.com/blog/2012-12-24/inheritance-oo-lua-44 [import]uid: 36792 topic_id: 33679 reply_id: 136295[/import]