Functions
Thinking of functions as reusable blocks of code, factory functions make easy work out of creating objects common to any Corona project.
The key component to making a factory function is the key word return. Functions can return values. When a function returns a value the functions ends immediately and any code following return is not executed. The value returned can be any value. In Lua, unlike many other languages, functions can return multiple values.
Functions can also receive values. The values received, often called arguments or parameters make functions really flexible.
Corona has many built in Factory functions, all under the display class. These functions all return a display object of varying types, text, rectangle, circle, image etc. If you are just making a simple object thee are good enough. Many times though, you will want to return a more specific type of object.
For example just creating a circle can be handled with the factory function: display.newCricle(left, top, radius), while useful is not usually the end of the process. Most often you will want to create a circle at a particular size, color and location. In these cases you’ll need more than display.newCircle(). For example:
local radius = math.random(10, 30) local circle = display.newCircle(0,0,radius) circle.x = math.random(30, 290) circle.y = math.random(30,450) local r = math.random(0, 255) local g = math.random(0, 255) local b = math.random(0, 255) circle:setFillColor( r, g, b )
Wow that’s a lot of code to make a circle of random size and color. We don’t want to have to repeat, or have it clog up the rest of our project logic.
Imagine expanding this into a loop that creates 30 circles.
for i = 1, 30, 1 do local radius = math.random(10, 30) local circle = display.newCircle(0,0,radius) circle.x = math.random(30, 290) circle.y = math.random(30,450) local r = math.random(0, 255) local g = math.random(0, 255) local b = math.random(0, 255) circle:setFillColor( r, g, b )
end
This works just fine, and there’s nothing wrong with it. But it could be improved in a few ways.
Leave well enough alone?
Of course not! Not when it comes to programming. This type of thinking gets you in more trouble than you can imagine. As your program grows being able to, identify and modify previously written code becomes essential. Using a factory function allows you to separate defining an object from creating the object.
Think of defining an object as determining all an object’s starting characteristics. While creating the object, creates a new instance of the object.
Making a circle Factory
Here’s a function that creates circles with random color, size and position.
local function make_circle() local radius = math.random( 10, 30 ) local circle = display.newCircle( 0, 0, radius ) circle.x = math.random( 30, 290 ) circle.y = math.random( 30, 450 ) local r = math.random( 0, 255 ) local g = math.random( 0, 255 ) local b = math.random( 0, 255 ) circle:setFillColor( r, g, b ) return circle end
The code above is essentially the original code snippet wrapped in a function. The key feature, and what makes this a factory, is the last line: return circle.
Internally the function creates a new shape object and stores it in the variable circle. This variable local to the function and not accessible outside of the function. Using the return keyword we can pass circle along to some other part of our program.
Making circles with make_circle()
Imagine we want to make 30 circles. With the new factory we now only need to add:
for i = 1, 30, 10 do local circle = make_circle() end
Why is this better than the first example:
Separating the code defining the circle objects from the code that actual creates them provides a couple advantages: It’s easier to understand and More flexible.
Easier to understand
When breaking code up like this if you need to change the look of the circle you can edit the make_circle function. Here you are altering only the default definition of the object which isn’t embedded along with other code.
More Flexible
Since we have a function that creates circles we can create circle from other areas of our program without having to duplicate code. Anytime you need a circle just call make_circle().
Color Object
Might as well improve on our system of setting the colors of objects. Rather than defining each of the color components, r, g and b, each time we need a color, we’ll wrap all of these up in a single object/table with properties r, g and b. Here’s a sample function:
local function Color( red, green, blue ) return {r=red, g=green, b=blue} end
The function above takes three values, combines them into a table. This table has properties of r, g and b. The function returns the table.
You might use it in this way. Imagine you wanted to create a color object representing the color red.
local red_color = Color( 255, 0, 0 )
You could then use the red_color in this way:
circle:setFillColor( red_color.r, red_color.g, red_color.b )
The beauty of this system is leads to better and more organized code in the future. With the color stored in an organized form we can start writing functions that transform our Color object by adjusting the hue, saturation and lightness. We can also share a Color object with other objects easily.
Random Color
Our system needs a random color. In this case we might as well make another function that will work with out Color object to return a random color.
local function random_color() local r = math.random( 0, 255 ) local g = math.random( 0, 255 ) local b = math.random( 0, 255 ) return Color( r, g, b ) end
Here define some random values for the red, green and blue color components then create a new color object from those values and return it.
Use this to further simplify the circle factory function:
local function make_circle() local radius = math.random( 10, 30 ) local circle = display.newCircle( 0, 0, radius ) circle.x = math.random( 30, 290 ) circle.y = math.random( 30, 450 ) local color = random_color() circle:setFillColor( color.r, color.g, color.b ) return circle end
Doesn’t look like a huge improvement, but it does more than you might think. By separating our code in this way our program can make colors and circles in a wider variety of circumstances.