Topic: Object Oriented Programming in Maratis(LUA)(Tutorial)

I have been trying to make some sense of object oriented programming in LUA (since lua doesn't really have object oriented programming).

WHAT IS OBJECT ORIENTED PROGRAMMING?

Object Oriented Programming(OOP) is taking variables and turning them into Objects. An Object is a variable that has TRAITS and ABILITIES. OOP is used to simulate real life objects. If we had a variable named:

apple =

An apple can have several traits. It has a TYPE and a COLOR and a TASTE. Apples don't have very many abilities except BeEaten().
OOP allows us to assign traits and abilities to your apple and can be used like this:

print (apple.type)
print (apple.color)
print (apple.taste)
apple:BeEaten()

Apples belong to the class of FRUIT, and that is why apples can have a taste and a color and a type. All objects can be CLASSFIED this way. All of the traits of an apple are inherited from the general traits of a fruit.

This is how you create a class and object in LUA:

--New Player Class
        function Player(name)
            local object = {}

            --Traits
            object.name = name
            object.hit= false

            txt_score = getObject("ScoreText")

            --Abilities
            function object:ShowHitStatus()
                setText (txt_score,object.name .. " got hit!")
            end    
                
            return object
        end

--Create Joe
local joe = Player("Joe")

--Create Bill
local bill = Player("Bill")

--Print Joe's name
print (joe.name)

--Show Bill's hit status
bill:ShowHitStatus()

The PLAYER CLASS is just a function named Player(). What this function does is creates a table named OBJECT and then it returns the table.

HOW DOES RETURN WORK?

Well, when you put an apple into a Blend() function, the blender returns a chopped up apple. But you don't have to always make a function return something. You can just have the blender Blend() and not give you back a chopped up apple. But most of the time when you put some fruit into a Blender, you want to be able to get the result (a nice smoothie perhaps?)

So what is actually occuring is that we are making the Player() function EQUAL TO "object" When you put an apple into the blender you get a chopped apple.

regular apple + Blend() function = chopped apple

(That isn't real code. hehe)

So, if Player() = object then when we type:

local joe = Player()

We are saying that joe = object

and if joe = object, then joe.name = object.name

And inside of the Player() funtion we made object.name = name

Then we took that "name" variable and made it an ARGUMENT of the Player() Function

WHAT IS AN ARGUMENT?

Going back the Blend() function, we can Blend() an apple like this:

Blend(apple)

Or we can blend an orange:

Blend(orange)

Or we can blend paper:

Blend(paper)

The things we swtich in and out of the Blend() function are called arguments.

When you put an argument in the parentheisis of the function, it gets plugged in everywhere the argument is found in the function

Example:

function Add(x,y)    
        result = x+y    
        return result
end

Add(1,2)

The 1 get's plugged in where the x is. The 2 get's plugged in where the y is.

Add(1,2)

should return 3

Add(978,562)

should return 1540

So, in our example of the Player() function, "name" is an argument, and whatever we plug in

Player(_here_) 

gets put:

function Player(_here_)
        print(_here_)
        setText(Text0,_here_)
end

and whatever/wherever else.

Here is the Class again:

--New Player Class
        function Player(name)
            local object = {}
            
            object.name = name
            object.hit= false
            txt_score = getObject("ScoreText")
            
            function object:ShowHitStatus()
                setText (txt_score,object.name .. " got hit!")
            end    
                
            return object
        end

--Create Joe
local joe = Player("Joe")

--Create Bill
local bill = Player("Bill")

--Print Joe's name
print (joe.name)

--Show Bill's hit status
bill:ShowHitStatus()

Functions work the same way. If bill = Player() and Player() = object (returns object) then object:ShowHitStatus = bill:ShowHitStatus.

Now that we have a PLAYER CLASS we can make any variable a PLAYER. And just by making them a PLAYER they will obtain the TRAITS and ABILITIES that every other PLAYER OBJECT has.

sarah= Player("Sarah Williams")
francais = Player("Francais Smith")
margret = Player("Margret Sachel")
sarah:ShowHitStatus()
francais:ShowHitStatus()
margret:ShowHitStatus()

Last edited by Tutorial Doctor (2013-11-27 22:45:04)

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

I made the example classes of lua. I hope someone will come in handy.
Classes, inheritance, and polymorphism.

--init class car

class_car = {}

function class_car:new(model, color)
    local object = {}
    object.model = model or "Nissan" --by default, Nissan
    object.color = color or "Red" -- by default, red

    setmetatable(object,self)
    self.__index = self
    return object
end

--create a car
my_auto = class_car:new("BMW",nil) --> we obtain: BMW Red

--create methods
function class_car:set(color)
    self.color = color
end

function class_car:get()
    return self.model, self.color
end

-- change the color of the car.
my_auto:set("BLACK")

--check:
print(my_auto:get()) --> BMW BLACK

--################## Inheritance ##############

class_moto = {} -- init class moto

--overriding a method (polymorphism)
function class_moto:get()
    return "2000", "year"
end

--inherit.
setmetatable(class_moto,{__index = class_car})

--create an instance of the class moto.
my_moto = class_moto:new()

my_moto:set("BLUE")

print(my_moto:get()) --> 2000 year (A call to a method on the child.)
print(class_car.get(my_moto))    --> Nissan BLUE (Call the parent method.)

Last edited by ant0n (2013-11-25 06:54:00)

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

When I get a chance, I am going to look at that code ant0n. Thanks for the post.

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

here's how you can make a class with methods.

base = {}
function base:new(x,y,z)
   local obj = {}
   obj.x = x or 0
   obj.y = y or 0
   obj.z = z or 0
   
   function obj:get()
      return self.x, self,y, self,z
   end

   self.__index = self
   return obj
end

object = base:new(10,10,10)
print (object:get()) -- result 10,10,10

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

Thanks for the tutorial !

but i'm still having big troubles understanding one thing :

How can you make two OO objects collide ? for example, with isCollisionBetween(cloneA, cloneB)

The only solution i found for now is making another table.insert in the metatable (yeah i know..)
then in onSceneUpdate, detect wich objects this is , with :

for i=0, #ListA do
    if isCollisionBetween(ListA[i], ListB[i]) then 
        Stuffhappenhere
    end
end

= horrible + result in hardcore fps drop after a few seconds. but everything else failed.

I'm kinda desperate with this. Any advices would be greatly appreciated

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

There is alot more involved in making a class library with lua, I personally just use
Middleclass

local class = require 'middleclass'

local Fruit = class('Fruit') -- 'Fruit' is the class' name

function Fruit:initialize(sweetness)
  self.sweetness = sweetness
end

Fruit.static.sweetness_threshold = 5 -- class variable (also admits methods)

function Fruit:isSweet()
  return self.sweetness > Fruit.sweetness_threshold
end

local Lemon = class('Lemon', Fruit) -- subclassing

function Lemon:initialize()
  Fruit.initialize(self, 1) -- invoking the superclass' initializer
end

local lemon = Lemon:new()

print(lemon:isSweet()) -- false

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

@ Vegas
I made another tutorial here:

http://forum.maratis3d.com/viewtopic.php?id=841

where I implement lua classes and also used the dofile() function. I actually created a clone in that tutorial.

It is basically up to how you design your class to work (which is possible since lua doesn't really have classes and that makes it more flexible).

For the clones you would certainly use the getClone() function perhaps alongside the clearForces() function.

@zester. Thanks for the post. I am going to look into Middleclass.

Last edited by Tutorial Doctor (2013-11-27 22:47:28)

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

Hmm not exactly what i needed, but i realise my explanations are very obscure,
i'm going to start another topic to not pollute yours. Thanks anyway!

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

Hi, Vegas! actually it is very simple smile

-- CREATE CLASS 1
apple_class1 = {}
function apple_class1:new(x,y,z)
    local o = {}
    o.mesh = getClone(getObject("apple"))
    o.x = x; o.y = y; o.z = z
    setPosition(o.mesh,{o.x,o.y,o.z})

    setmetatable(o,self)
    self.__index = self
    return o
end
-- create an instance of the class 1.
apple = apple_class1:new(1,0,1)

-- CREATE CLASS 2
apple_class2 = {}
function apple_class2:new(x,y,z)
    local o = {}
    o.mesh = getClone(getObject("apple2"))
    o.x = x; o.y = y; o.z = z
    setPosition(o.mesh,{o.x,o.y,o.z})
    
    function o:update()
        --**************** COLLISIONS! ******************************
        if isCollisionBetween(apple.mesh,self.mesh) then -- apple.mesh -> apple = apple_class1:new(1,0,1)
            print("COLLIDED!")
        end
    end
    
    setmetatable(o,self)
    self.__index = self
    return o
end
-- create an instance of the class 2.
apple2 = apple_class2:new(10,0,1)

--UPDATE
function onSceneUpdate()

    apple2:update() -- apple_class2 -> function o:update()

end

if you have questions, ask. I will be glad to help.

Last edited by ant0n (2013-11-28 13:50:33)

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

Hey ant0n (wow it feel weird, that's also my name tongue)

Thanks, that's exactly what i'm aiming for ! could it be adapted to this method ?
Because all my spawning patterns are already made under this model (for a shoot'em'up game)
Here's the details :

PlayerBulletModel = getObject("PlayerBullet")

-- PlayerBullet object
PlayerBullet = {}
PlayerBullet.__index = PlayerBullet

function PlayerBullet.create(pos)

    local ball = {} -- our new object
    setmetatable(ball, PlayerBullet) -- set metatable
  
    ball.object = getClone(PlayerBulletModel)

    setPosition(ball.object, pos)

    return ball
end

function PlayerBullet:update() -- behavior
    if isCollisionBetween(self.object, EndWall) then 
        deactivate(self.object)
    end
end

-- PlayerBullets list
bulletList = {}
function addPlayerBullet(pos)
    table.insert(bulletList, #bulletList + 1, PlayerBullet.create(pos))
end

Then in onSceneUpdate :

    for i=1, #bulletList do bulletList[i]:update() end 

And to create a clone:

addPlayerBullet({0, 0, 0})

Thanks for your help wink

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

Vegas wrote:

wow it feel weird, that's also my name

unexpectedly... big_smile

I would do this:

PlayerBullet = {}
k = 1  -- counter bullets
function PlayerBullet:create(x,y,z)

    local ball = {}
    ball.object = getClone(getObject("PlayerBullet"))
    ball.x = x; ball.y = y; ball.z = z
    setPosition(ball.object,{ball.x,ball.y,ball.z})
    
    function ball:update()
        if isCollisionBetween(self.object, EndWall) then 
            deactivate(self.object)
        end    
    end

    k = k+1
    
    setmetatable(ball,self)
    self.__index = self
    return ball

end

bullet = {}

Then in onSceneUpdate :

function onSceneUpdate()

    --************* create a clone: ***************
    if isKeyPressed("SPACE") then
        bullet[k] = PlayerBullet:create(0,0,0)
    end 
    
    --********** update a clone **********
    for i =1, #bullet do
        bullet[i]:update
    end 

end

Last edited by ant0n (2013-11-29 02:17:45)

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

Right, looks like the best way to go, unfortunately i'm unable to make collisions
between two objects like in your #9 post hmm
hell, i'm definitely not a script guy

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

if you have shown your .lua file, I would try to understand it smile

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

I made test in a empty project, just took the script you posted , duplicated it and renamed some stuff ;
Script (some lines space might be broken)

i tried to make use of isCollisionBetween(object, object) everywhere i could, with  :

self.object
Apple.object
appleList[count]
appleList[i]
appleList[1]
for i=0, #appleList do

I also tried to rename

    self.__index = self

As they where the same in both class (that changed nothing)

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

You need to check collision appleList and bullet?
if Yes, then you need to do so
in the class bullet:

  function ball:update()    
        translate(self.object, {-0.5, 0, 0}, "local") 
    
        for i=1,#appleList do -- iterating through all instances appleList class Apple.
            if isCollisionBetween(self.object, appleList[i].object) then 
               deactivate(self.object)
            end   
        end         
  end

here's the entire code. Just in case wink

Apple = {}
count = 1  -- counter appleLists
function Apple:create(x,y,z)

    local app = {}
    app.object = getClone(getObject("Apple"))
    app.x = x; app.y = y; app.z = z
    setPosition(app.object,{app.x,app.y,app.z})
    
    function app:update()
        
    end

    count = count+1
    
    setmetatable(app,self)
    self.__index = self
    return app

end

appleList = {}

    --[[                    CLASS2            ]]
PlayerBullet = {}
k = 1  -- counter bullets
function PlayerBullet:create(x,y,z)

    local ball = {}
    ball.object = getClone(getObject("PlayerBullet"))
    ball.x = x; ball.y = y; ball.z = z
    setPosition(ball.object,{ball.x,ball.y,ball.z})
    
    function ball:update()
    
        translate(self.object, {-0.5, 0, 0}, "local") 
    for i=1, #appleList do
        if isCollisionBetween(self.object, appleList[i].object) then 
            deactivate(self.object)
        end    
    end
        
    end

    k = k+1
    
    setmetatable(ball,self)
    self.__index = self
    return ball

end

bullet = {}

    --[[                    SCENE UPDATE            ]]
function onSceneUpdate()

    --********** update a clone **********
    for i =1, #bullet do bullet[i]:update() end 
    for i =1, #appleList do appleList[i]:update() end 
    
    --************* create a clone: ***************
    if onKeyDown("SPACE") then
        bullet[k] = PlayerBullet:create(0,0,0)
        appleList[count] = Apple:create(-20,0,0)
    end 

end

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

I hope this will help you understand:

Apple = {}
function Apple:create(name, color)
    local app = {}
    app.color = color 
    app.name = name
    app.mass = 10
    
    setmetatable(app,self)
    self.__index = self
    return app
end

appleList = {}

-- CREATE INSTANCE
appleList[1] = Apple:create("apple1", "red")
appleList[2] = Apple:create("apple2", "green")

-- PROFIT!
print ("name="..appleList[1].name.." color="..appleList[1].color.." mass="..appleList[1].mass) 
-- RESULT          name=apple1 color=red mass=10

print ("name="..appleList[2].name.." color="..appleList[2].color.." mass="..appleList[2].mass) 
-- RESULT          name=apple2 color=green mass=10

Last edited by ant0n (2013-11-30 14:47:30)

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

Perfect ! Thanks so much !! *cry*
This stuff bugged me for so long !

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

I am glad I could help...
by the way, I made a typo in the previous example.
in Apple:create(name, color) instead::

app.color = red

you need to:

app.color = color

fixed that.

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

Good example ant0n (post # 16)

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

thanks Tutorial Doctor! wink

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

Hi ant0n, there's a last problem ;

The crazy frame rate drop still exist, but i think i know what is it.

In my theory that's because the items in the table stay active all the time.
When you have a long behavior for an object, even if the object got deactivated, the entry in the table is not, and it's still running in the background, so it's almost  the same as if the object wasn't deactivated.
Then after a while, the table just gets too big and the game crash no matter what.

Note it's only my theory, maybe it's a lot of bull. But i don't see what else it can be

For now i've tried to remove items from the table/reset the table when my object collide with another object
but as usual, nothing worked.

Looks like i need your help again hmm

I could upload a test project if u wish

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

Hi Vegas!

I could upload a test project if u wish

Yes, it will be easier for us to deal with it. smile

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

Right, i cleaned everything and keep the fastest way to make the game bug

Test Project

Press "S" to spawn clones, they will follow a path. I used
isCollisionBetween() -> setBehaviorVariable()

It's starting to freeze when i spawned about 27~

If that's not enough i can  upload another example later, where the same freeze stuff happen when shooting some projectiles. It just take something like 150~ clones to start freezing but in the end the result is the same
   
Sidenote, I'll be back late today, got stuff to do sad

Thanks for your help !

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

finish! I spawned about 200 clones and all works well!
And I made a small optimization in the code, now Spawnpoints.lua looks shorter. wink
testarea.7z

Last edited by ant0n (2013-12-06 08:06:43)

Re: Object Oriented Programming in Maratis(LUA)(Tutorial)

Great ! you even fixed my spawpoints, i always wondered how to spawn clones like that, thanks alot wink