Display Objects / custom component question

This question is coming from a Flash Developer background. I was wondering how to create custom view components. In other words I would like to create a ship.lua module and then use it in my game.

My main lua file could then require the file and I could do things like the following.

[lua]local ship = require("ship)

ship.new() --would create a new instance or display object such as an image and add it to the display

–I would of course like to set the X and Y of the ship or display object simply by setting an x and y value
ship.x = display.contentWidth / 2
ship.y = display.contentHeight / 2[/lua] [import]uid: 6636 topic_id: 3515 reply_id: 303515[/import]

Hi, here’s a simple example of how to proceed:

-- ship.lua  
module(..., package.seeall)  
  
local background  
  
function new()  
 background = display.newRect(0,display.screenOriginY, display.contentWidth, display.contentHeight-display.screenOriginY)  
 background:setFillColor(255, 255, 255)   
end  
  
function setColor( r, g, b )  
 background:setFillColor(r, g, b)  
end   
-- main.lua  
local ship = require("ship")  
  
ship.new()   
ship.setColor(0, 255,0)  

Tim [import]uid: 8196 topic_id: 3515 reply_id: 10596[/import]

so in the case of ship would I have to create functions for setting all the other values as well such as X, Y, Alpha and so on ? [import]uid: 6636 topic_id: 3515 reply_id: 10597[/import]

Actually, Tims’ example is good, this one allows you to spawn off as many ships as you want (this is to get you started but you will get the picture)

module(..., package.seeall)  
  
 local metat = { \_\_index = {} }  
  
function new(x,y,w,h)  
 local c = display.newRect(x,y,w,h)  
 local h = setmetatable({ c = c }, metat)  
 return h  
end  
   
function metat.\_\_index:setColor( r, g, b )  
 self.c:setFillColor(r, g, b)  
end   
  
function metat.\_\_index:getX()  
 return self.c.x ;  
end   
  
function metat.\_\_index:setX(xx)  
 self.c.x = xx;  
end   
  

Then in another lua file

[code]
local ship = require(“ship”)

local s = ship.new(10,100,100,20)
s:setColor(0, 255,0)
s:setX(xVal);

local b = ship.new(40,40,200,30);
b:setColor(255,255,0);
print (b:getX())

[/code] [import]uid: 24 topic_id: 3515 reply_id: 10603[/import]

carlos…

i came up with something similar without metatable or __index. it works, so please could you help me understand why i might need those? (in my other class implementation i did use those, but they work without them here. maybe it’s why i need to use “this” in my code?)

I’ve seen about 3 ways of doing “classes” but this one below seems quite good to me.

(I’m new to all this though, so i don’t know if i’ve got elements in there which are not optimal for speed)

file: BallActor.lua
[lua]module(…, package.seeall)

TableUtils = require(“TableUtils”)

function new(x,y,img) – Constructor

local this = {}

– private vars, but synthesized with getter/setter on this,
– to make them public on object
local group
local contacts
local sprite

– private, not synthesized below
local groupRedefined

– create the graphic for the actor
sprite = display.newImage(img);
sprite.x = 60 + math.random( 160 )
sprite.y = -100
sprite.type= string.gsub(img, “.png”,"")
sprite.is = “BallActor”

– initalize collision info
group = {this}
contacts = {}

– synthesize public variables (getter/setter)
this.sprite = sprite
this.actor = this
this.sprite.actor = this
this.group = group
this.contacts = contacts

function this:say()
print("I am a BallActor with sprite id = "…sprite.id)
end

function this:resetGroup()
group = {this}
groupRedefined = false
end[/lua]

main.lua:
[lua]function newBall()

local rand = math.random( 100 )

local x = 60 + math.random(160)
local y = -100

local ball

if(spriteCount < MAX_BALLS) then

– create instance of BallActor “class” (this isn’t a display object, but includes a sprite reference)
ball = BallActor.new(x,y,“ball.png”)

spriteCount = spriteCount+1
ballIDCount = ballIDCount+1

– sprite variable is “synthesised” in our BallActor class (ObjC terminology)
– basically means it is public variable on the class instance
ball.sprite.id = ballIDCount

– call a public class method
ball.say()

print(“sprite=”…tostring(ball.sprite))
print(“sprite.id=”…ball.sprite.id)

world:insert(ball.sprite)
_.push(balls,ball)

physics.addBody(ball.sprite)

end

end

local dropBall = timer.performWithDelay( 50, newBall,-1)[/lua]

thanks for any feedback
J [import]uid: 6645 topic_id: 3515 reply_id: 10606[/import]

by the way which is better

[lua]this.say=function(whatever)
print("I am a BallActor with sprite id = "…sprite.id)

if(whatever~=nil) then
print(“whatever=”…whatever)
end
end[/lua]
called with this.say(“something”)

or

[lua]function this:say(whatever)
print("I am a BallActor with sprite id = "…sprite.id)

if(whatever~=nil) then
print(“whatever=”…whatever)
end

end[/lua]
called with this:say(“something”)
(note in my original code i was calling ball.say() but it should’ve been ball:say(), because adding arguments doesnt work in the first case the way i had it defined… however both the 2 functions above work if called as suggested) [import]uid: 6645 topic_id: 3515 reply_id: 10609[/import]

Am pretty sure that at the end of your new in BallActor.lua you do a return this?

return this  
end  

This is another way of doing it. Your *this* member basically copying the members of your new class.

local sprite = display.newImage("....")  
this.sprite = sprite  

Therefore, on your main.lua file

ball = BallActor.new(...)  
ball.sprite.id = ballIDCount -- is totally acceptable because in the BallActor.lua, the \*this\* made a copy of the sprite and is now exposed.  

As for p4mance… Good Q. I never really tried out p4mance on tables…

Carlos [import]uid: 24 topic_id: 3515 reply_id: 10610[/import]

yes my code got cut off. that is what is at the end.

thanks
j [import]uid: 6645 topic_id: 3515 reply_id: 10614[/import]

+1 for this:say(“something”) just for style reasons. Beyond style both seem the same to me technically. [import]uid: 7356 topic_id: 3515 reply_id: 10617[/import]

looks like there are hidden control characters in my pasted sample code.

see if you editor can show them. then just delete them.

c [import]uid: 24 topic_id: 3515 reply_id: 10618[/import]

@magenda +1 [import]uid: 24 topic_id: 3515 reply_id: 10620[/import]

Actually, Tim’s no-OOP style in #1 post supports multiple ships too:

[lua]-- ship.lua
module(…, package.seeall)

function new()
ship= display.newImage("")
function ship:customize(args)
ship.property=arg
end
return ship
end
– main.lua
local ship = require(“ship”)

ship1=ship.new()
ship2=ship.new()

ship1:customize(args)
ship2:customize(args) [/lua] [import]uid: 7356 topic_id: 3515 reply_id: 10627[/import]

with carlos’ method I don’t think you can have private variables directly, since local variables to the module are static.

however you can use private[self] for instance to replicate a private variable per instance

there’s an example of that in my ParallaxLayer.lua code here
http://developer.anscamobile.com/forum/2010/11/09/modules-vs-classes

note having the extra “private” table and instance variables will slow things down again, but that is expected i guess
[import]uid: 6645 topic_id: 3515 reply_id: 10626[/import]

@jmp909

so am going to b a smart **s

what if you tried

function new(x,y,w,h)  
   
 local this = {shape = display.newRect(x,y,w,h)}  
 setmetatable(this, Ship.mt);   
 return this  
   
end  

i haven’t tried it but i would surmise p4mance would b better [import]uid: 24 topic_id: 3515 reply_id: 10628[/import]

of course… you’re the boss :wink:

the less commands and variables over 500,000 instances the better the performance for sure.

thanks for the feedback… this is helping me understand the differences

in reality we dont need private variables anyway, i am just trying to slowly drop my AS3 best practices :slight_smile:

j. [import]uid: 6645 topic_id: 3515 reply_id: 10629[/import]

500000 ships (same one repeated)
your method 11.5s
my original method 13.4s

then i rewrote your example in a slightly more readable syntax (below). the performance is nearly the same as yours now (it’s the same structure more or less, i just renamed the prefix to Ship and separated out the object passed to the metatable, this slows it down to 11.7s rather than 11.5)

regards
j

[lua]module(…, package.seeall)

Ship = {};
Ship.mt = {};
Ship.mt.__index = Ship;
function new(x,y,w,h)

local this = {}

local shape = display.newRect(x,y,w,h)

– public getter/setter
this.shape = shape

setmetatable(this, Ship.mt);
return this

end

function Ship:setColor( r, g, b )
self.shape:setFillColor(r, g, b)
end

function Ship:getX()
return self.shape.x ;
end

function Ship:setX(xx)
self.shape.x = xx
end

return this

end[/lua] [import]uid: 6645 topic_id: 3515 reply_id: 10615[/import]

So in this example. How would you go about setting alpha and x dynamically as you did in the other more verbose examples? [import]uid: 9457 topic_id: 3515 reply_id: 10792[/import]

So in this example, could you explain the metat.__index stuff etc please.

[lua]module(…, package.seeall)

local metat = { __index = {} }

function new(x,y,w,h)
local c = display.newRect(x,y,w,h)
local h = setmetatable({ c = c }, metat)
return h
end

function metat.__index:setColor( r, g, b )
self.c:setFillColor(r, g, b)
end

function metat.__index:getX()
return self.c.x ;
end

function metat.__index:setX(xx)
self.c.x = xx;
end [/lua]
cheers [import]uid: 9457 topic_id: 3515 reply_id: 10794[/import]

with my example:
[lua]ship.shape.x = 100
ship.shape.alpha = 0.5[/lua]
with their example:
[lua]ship:setX(100)
ship:setAlpha(0.5)[/lua]
in which case you’d have to include this function in the class:
[lua]function metat.__index:setAlpha(a)
self.c.alpha = a;
end [/lua]

basically the metatable’s __index is a pointer back to the object

hence why i use
Ship.mt.__index = Ship
so that i can then define my functions with Ship: rather than metat.__index:

it looks more readable

the metatable __index is explained here:
http://defunside.blogspot.com/2006/10/oop-in-lua.html



Account = {balance=0}

function Account:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end

function Account:withdraw(v)
self.balance = self.balance - v
end

The first line creates a table Account with variable balance.
Next, a function is defined to live in Account. The ‘new’ function
accepts a table and makes self, Account, the metatable for o.

Lastly, set__index to self, Account, as well and return the table o.
Now we can create a new object and use the Account methods
and variables:

a = Account:new{balance = 10}
a:withdraw(5)
print(a.balance)

The above passes the table {balance=10} to new,
overwriting balance=0. Now the sexy part happens.
a tries to call withdraw, but has no withdraw element in it’s table.
When Lua tries to find something in a table and it is missing it checks
if it has a metatable and if that has index defined.
If so it then goes to the table
index points to and searches for the element.
In this example it goes to the Account table and finds withdraw,
the withdraw call basically turns into:

Account.withdraw(a, 5)

Objects! Woooo.



[import]uid: 6645 topic_id: 3515 reply_id: 10816[/import]

I am looking for a way to have a display object cloned (by dozens) without much cpu overhead, as this process will be very often used in my game. In the methods discussed here, the display object is always re-created from the beginning inside new(). That costs too much…

Is there a different way to have the display object created only once (outside new() ) and then “copy” it by value to produce an additional instance of the “class” ? [import]uid: 7356 topic_id: 3515 reply_id: 12707[/import]