OOP + Runtime Question

So I’m painfully trying to follow a loose OOP methodology from my previous Spaghetti code development.

I’ve crated a class called Orb, which has a drop method attached:

function Orb:drop()  
 if self.move == true then  
 --print("i: "..i)  
 --print("orbs[i].y: "..orbs[i].y)  
 --print("LESS THEN")   
 --calculatePos(orbs[i])  
  
 if self.move == true and self.image.y \< 400 then  
  
 self.image:translate(0,self.weight)  
 else  
 print("DONT MOVE")  
 self.move = false  
 --Runtime:removeEventListener("enterFrame", dropOrbs)  
 --dumpOrbs()  
 end  
 end  
end  

The idea being that Orbs will drop from the top of the screen to the bottom; however I’m struggling to think how I attach a Runtime listener to this method.

Any help would be much appreciated - pulling my hair out at the moment.

MTIA [import]uid: 33275 topic_id: 33208 reply_id: 333208[/import]

A Runtime event listener will infinately spawn orbs… Try using a timer instead…

timer.performWithDelay( 1000, dropOrbs, -1 )  

This would drop an orb every seccond…

Hope this answered your question… [import]uid: 144504 topic_id: 33208 reply_id: 131936[/import]

Thanks for the input - however, I only want the runtime attached to the drop method not the spawn method.

I guess a timer could work, but I’m intrigued as to whether or not this type of approach could work - I like the idea of an Orb instance having its own listeners.

And timers I find kinda messy. But thanks again for your help. [import]uid: 33275 topic_id: 33208 reply_id: 131937[/import]

I think a runtime listener would infinately spawn orbs until you removed it, though, wouldn’t it? [import]uid: 144504 topic_id: 33208 reply_id: 131938[/import]

So I found this works, but it’s pretty abstract and not sure it’s ideal:

I renamed Orb:drop() to Orb:enterFrame

In main.lua where I’m currently creating the instances from class Orb I have this:

local function createLine()  
 for i = 1,8 do  
 orbGroup[#orbGroup+1] = orbs.new(xPos, yPos)  
 local dropTheOrbs = orbGroup[i]  
 Runtime:addEventListener("enterFrame", dropTheOrbs)  
 xPos = xPos + 40  
 if xPos \> 320 then  
 xPos = 20  
 end  
  
 end  
end  

It’s not pretty and I’m pretty sure there has to be a more elegant solution - but it is at least working as intended. [import]uid: 33275 topic_id: 33208 reply_id: 131939[/import]

Seems as though I talked too soon :slight_smile:

So a little more background - I have a button that spawns 8 Orbs at the top of the screen, which then drop to the bottom.

This all worked fine for the first attempt - but pressing the button a second time spawns the second line of Orbs, however they don’t drop to the bottom like the first line.

Back to pulling out hair :slight_smile: [import]uid: 33275 topic_id: 33208 reply_id: 131940[/import]

Are you using physics to drop the orbs?
[import]uid: 144504 topic_id: 33208 reply_id: 131943[/import]

Nope, no physics involved - all ol’fashioned programatic animations. [import]uid: 33275 topic_id: 33208 reply_id: 131946[/import]

The reason behind the second line not working was because of this:

local dropTheOrbs = orbGroup[i]

The i from the for loop was always referring to 1-8 - so the second line of Orbs which would be 9-16, wouldn’t be affected.

I have now changed this to:

local function createLine()  
 --dropTheOrbs()  
 for i = #orbGroup+1,#orbGroup+8 do  
 orbGroup[#orbGroup+1] = orbs.new(xPos, yPos)  
 local dropTheOrbs = orbGroup[i]  
 Runtime:addEventListener("enterFrame", dropTheOrbs)  
 xPos = xPos + 40  
 if xPos \> 320 then  
 xPos = 20  
 end  
  
 end  
 --Runtime:addEventListener("enterFrame", dropOrbs)  
end  

Which is working - but again this doesn’t exactly seem very neat in an OOP kinda way. [import]uid: 33275 topic_id: 33208 reply_id: 131947[/import]

I would approach this differently:

local function dropOrbs()  
 for i = 1, #orbGroup do  
 orfbGroup[i]:drop()  
 end  
end   
  
local function createLine()  
 for i = #orbGroup+1,#orbGroup+8 do  
 orbGroup[#orbGroup+1] = orbs.new(xPos, yPos)  
 xPos = xPos + 40  
 if xPos \> 320 then  
 xPos = 20  
 end  
   
 end  
end  
  
createLine()  
Runtime:addEventListener("enterFrame", dropOrbs)  
  

or something like that. If I’m reading this correctly you have an array of orb objects (orbGroup), you spawn a new 8 each time. You’re code to drop a single orb is in orb:drop().

You only want to create one Runtime listener. Your code was creating multiple runtime listners (which of course you can do, but you have to also remove them when your object goes away). enterFrame wants a function, not an object and you were trying to pass the object in, not a method to run each frame. [import]uid: 19626 topic_id: 33208 reply_id: 131950[/import]

You can also play around with Closures:

function wrapParam(func, param)  
 return function(...)  
 return func(param, ...)  
 end  
end  

This little function allows you to generate a new function from an existing one that has 1 parameter already assigned.

so then when constructing an orb you do:

--Assuming you have a variable 'orb' that is of type Orb  
Runtime:addEventListener("enterFrame", wrapParam(orb.drop, orb))  

Which will call drop with the signature ‘orb.drop(self, event)’ or ‘orb:drop(event)’ (these are the same) since wrapParam supplies the self parameter, and so event moves down into the second parameter [import]uid: 134101 topic_id: 33208 reply_id: 131954[/import]

Wow Ntero - you’ve just completely blown my mind, in a good way :slight_smile: I’m going to have to go away and have a good read about closures, always just assumed these were just anonymous funcitons but clearly not.

Robmiracle - from your suggestion it seems as though I would have to take the drop ‘behaviour’ out of the Orb class, which probably is a good idea. [import]uid: 33275 topic_id: 33208 reply_id: 131955[/import]

The difference between a closure and an anonymous function has to do with the concept of upvalues. The idea being that the returned function has access to the variable ‘param’ from an entirely different scope relative to where it’s called from. Some languages allow you to maintain the reference scope from where it was declared, and not from where it’s being called from, C# and Lua being the two I’m most familiar with. That and metamethods are probably my two favourite Lua features that help make it stand above most other interpreted languages.

There is one other Closure helper function I use a lot:

function generateCommand(func, ...)  
 local temp = {n=select('#', ...), ...}  
 return function()  
 return func(unpack(temp, 1, temp.n))  
 end  
end  

This one allows you to attach as many parameters as you want to be invoked later. i.e. generateCommand(print, “This”, “is”, “a”, “Test”) will give you a parameterless function that when invoked will call print(“This”, “is”, “a”, “Test”). The downside to this one is that it won’t accept any parameters later, meaning that to use this instead would mean you’d lose the event from a Corona Event. temp is a single upvalue that stores all parameters in a table (and n, being the number of parameters stored, otherwise a nil in the middle of the parameters would break it), and is accessible to the returned function (and only the returned function, effectively) regardless of where it is invoked.

edit: in the previous wrapParam example, the fact that you can access func and param inside of function(…) is the unique part, since that function, and stack memory are long gone by the time you call the function. Those two variables are accessible to the function variable for it’s entire lifetime. If you want to get very tricky, we do a few instances in our own code with hand offs, where a chain of functions pass their upvalues (usually callbacks at the end of the chain) down the chain of function calls, which means that 5 anonymous function calls later you can still access variables given to you in the first function call, without actually having to store them anywhere (each new function declaration can access the upvalue if it’s within the scope the function was declared in). It helps us write very little code for sometimes very complex sequential actions. [import]uid: 134101 topic_id: 33208 reply_id: 131965[/import]

You’re not really dropping the move/drop code from the object, you’re just maintaining a list of objects and iterating over it calling each object’s drop method. Still object oriented and the object is still in control of it’s actual movement.

If you wanted to do this without a runtime listener, you could simply have the drop method do a transition.to() instead of moving it a fixed amount. [import]uid: 19626 topic_id: 33208 reply_id: 131968[/import]

A Runtime event listener will infinately spawn orbs… Try using a timer instead…

timer.performWithDelay( 1000, dropOrbs, -1 )  

This would drop an orb every seccond…

Hope this answered your question… [import]uid: 144504 topic_id: 33208 reply_id: 131936[/import]

Thanks for the input - however, I only want the runtime attached to the drop method not the spawn method.

I guess a timer could work, but I’m intrigued as to whether or not this type of approach could work - I like the idea of an Orb instance having its own listeners.

And timers I find kinda messy. But thanks again for your help. [import]uid: 33275 topic_id: 33208 reply_id: 131937[/import]

I think a runtime listener would infinately spawn orbs until you removed it, though, wouldn’t it? [import]uid: 144504 topic_id: 33208 reply_id: 131938[/import]

So I found this works, but it’s pretty abstract and not sure it’s ideal:

I renamed Orb:drop() to Orb:enterFrame

In main.lua where I’m currently creating the instances from class Orb I have this:

local function createLine()  
 for i = 1,8 do  
 orbGroup[#orbGroup+1] = orbs.new(xPos, yPos)  
 local dropTheOrbs = orbGroup[i]  
 Runtime:addEventListener("enterFrame", dropTheOrbs)  
 xPos = xPos + 40  
 if xPos \> 320 then  
 xPos = 20  
 end  
  
 end  
end  

It’s not pretty and I’m pretty sure there has to be a more elegant solution - but it is at least working as intended. [import]uid: 33275 topic_id: 33208 reply_id: 131939[/import]

Seems as though I talked too soon :slight_smile:

So a little more background - I have a button that spawns 8 Orbs at the top of the screen, which then drop to the bottom.

This all worked fine for the first attempt - but pressing the button a second time spawns the second line of Orbs, however they don’t drop to the bottom like the first line.

Back to pulling out hair :slight_smile: [import]uid: 33275 topic_id: 33208 reply_id: 131940[/import]

Are you using physics to drop the orbs?
[import]uid: 144504 topic_id: 33208 reply_id: 131943[/import]