All drawing that occurs on the screen is accomplished by creating DisplayObjects. Anything that appears on the screen is an instance of a DisplayObject. You don’t actually create these objects directly. Instead, you create special kinds of DisplayObject such as rectangles, circles, images, text, etc.
These objects are all first-class citizens. You can animate them, turn them into buttons, etc.
You create a DisplayObject by calling a special kind of function called a constructor. This implicitly adds the object above all other objects you have created. DisplayObjects are designed to organize common functionality, but you never create a DisplayObject explicitly.
Instead, there are constructors for each specific kind of DisplayObject, e.g. display.newRect() creates a VectorObject.
All display object constructors implicitly set the parent of the new objects to be the current stage object. (Currently, there is only one stage in Corona. Groups can be created to act like additonal stages for grouping objects.) Most have an optional parentGroup parameter that overrides this behavior and instead sets the parent to a specified group.
All instances of DisplayObject behave similarly to normal Lua tables. This means you can add your own properties to the object as long as they don't conflict with the properties and method names below. Group objects (and stage objects) have some slight quirks, as discussed below; also see the more detailed technical discussion in "Display Objects vs. Tables" at the end of this section.
In addition, all display objects have the following properties and object methods in common:
Properties are accessed via the dot operator. For example, if we have a DisplayObject represented by the variable object, we can change its alpha to 50%: object.alpha=0.5.
Below are the common properties shared by all display objects.
object.alpha is the object's opacity. A value of 0 is transparent and 1.0 is opaque. The default value is 1.0.
Note that this is a different alpha property than the optional "alpha" component found in each color specification of the form (r, g, b [, a]). In the latter case, the alpha range is 0-255, just like the red, green and blue ranges, because the resulting value set specifies a 32-bit color with 8 bits per channel.
object.height is in local coordinates
object.isVisible controls whether the object is visible on the screen. true is visible and false is not.
object.isHitTestable allows an object to continue to receive hit events even if it is not visible. If true, objects will receive hit events regardless of visibility; if false, events are only sent to visible objects.
object.length [read-only] is deprecated in favor of group.numChildren. For Group Objects, this is the number of children; 0 otherwise.
object.parent [read-only] returns the parent group of the object.
object.rotation is the current rotation angle (in degrees).
object.contentBounds is a table with properties xMin, xMax, yMin, yMax in screen coordinates. Generally used to map the object in a group to the screen coordinates.
object.contentHeight is the height in screen coordinates.
object.contentWidth is the width in screen coordinates.
object.width is in local coordinates
object.x specifies the x-position (in local coordinates) of the object relative to the parent — the parent’s origin to be precise. Specifically, it provides the x-position of the object’s reference point relative to the parent. Changing the value of this will move the object in the x-direction. Changing the object's reference point will change the object's x and y points without moving the object.
object.xOrigin specifies the x-position of the object’s origin relative to the parent’s origin. It is in the object’s local coordinates. Changing the value of this will move the object in the x-direction.
object.xReference defines the x-position of the reference point relative to the object’s local origin. It is relative to another point in the object, not to its parent. Conceptually, the reference point is the location about which scaling and rotations occur. Sometimes this is referred to as the registration point. For most display objects, this value defaults to 0, meaning the x-position of the origin and the reference point are the same. This merely defines the reference point, so changing the value of this property does not change the position of the object.
object.xScale gets or sets the X scaling factor. A value of 0.5 will scale the object to 50% in the X direction.
object.y specifies the y-position (in local coordinates) of the object relative to the parent — the parent’s origin to be precise. Specifically, it provides the y-position of the object’s reference point relative to the parent. Changing the value of this will move the object in the y-direction. Changing the object's reference point will change the object's x and y points without moving the object.
object.yOrigin specifies the y-position of the object’s origin relative to the parent’s origin. It is in the object’s local coordinates. Changing the value of this will move the object in the y-direction.
object.yReference defines the y-position of the reference point relative to the object’s local origin. It is relative to another point in the object, not to its parent. Conceptually, the reference point is the location about which scaling and rotations occur. Sometimes this is referred to as the registration point. For most display objects, this value defaults to 0, meaning the y-position of the origin and the reference point are the same. This merely defines the reference point, so changing the value of this property does not change the position of the object.
object.yScale gets or sets the Y scaling factor. A value of 0.5 will scale the object to 50% in the Y direction.
Object methods are accessed via the colon operator. For example, if we have a DisplayObject represented by the variable object, we can translate the object 10 pixels to the right (of it's current position): object:translate( 10, 0 ).
Below are the common methods shared by all display objects:
object:getParent() is deprecated in favor or object.parent. (Yes, you should ignore the fact that sample code continues to use this API).
object:rotate( deltaAngle ) effectively adds deltaAngle (in degrees) to the current rotation property.
object:scale( sx, sy ) effectively multiplies xScale and yScale properties by sx and sy respectively. If the current xScale and yScale values are 0.5 and sx and sy are also 0.5, the resulting scale will be 0.25 for xScale and yScale. This scales the object from 50% of it's original size to 25%.
object:setReferencePoint( referencePoint ) sets the reference point either to the center of the object (default) or to one of several convenient points along the bounding box of the object. The argument referencePoint should be one of:
By design, an object's reference point is statically positioned relative to the object's local origin. This means that if you explicitly set an object's reference point using setReferencePoint() and then later modify the height or width of the object, the reference point may no longer refer to the same point.
Changing the object's reference point will change the object's x and y values without moving the object.
This can cause unexpected results, especially when working with text objects: assigning a different string to the object's text property changes the object's width, but not its reference point, which changes the object's alignment. The workaround is to reset the object's reference point and x-position after assigning the new string. The following code illustrates this behavior and workaround. (These concepts also apply to other types of display objects, such as image and shapes.)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | -- A text object is created and is aligned left at point x=20 local textObj = display.newText("A short string", 0,0, nil, 14); textObj:setReferencePoint(display.CenterLeftReferencePoint); textObj.x = 20; -- Later, the textObj.text property is assigned a new string value of different length, -- causing the object's width to change, but not its reference point. -- Consequently, the text is no longer aligned left at point x =20 textObj.text = "This string has several more characters than before..." -- Work-around: -- Reset the text object's reference point and x position -- after you update its text property: textObj.text = "This string has several more characters than before..." textObj:setReferencePoint(display.CenterLeftReferencePoint); textObj.x = 20 |
object:translate( deltaX, deltaY ) effectively adds deltaX and deltaY to the x and y properties respectively. This will move the object from it's current position.
object:removeSelf( ) removes the display object and frees its memory, assuming there are no other references to it. This is equivalent to calling group:remove(IndexOrChild) on the same display object, but is syntactically simpler. The removeSelf() syntax is also supported in other cases, such as removing physics joints in Physics.
See the section on removing objects properly in the Application Programming Guide for more on memory management and display object removal.
Bitmap image objects are a type of DisplayObject.
display.newImage( filename [, baseDirectory] [, left, top] ) Returns an image object. It loads the image data from filename and by default looks in the system.ResourceDirectory for that file. If you specify the argument baseDirectory it will look in that directory instead (see system.pathForFile for valid values of baseDirectory). Both PNG and JPEG files are supported.
myImage = display.newImage( "image.png", 10, 20 ) myImage2 = display.newImage( "image.png" )
You can optionally specify that the image's top-left corner be located at the coordinate (left, top); if you don't supply both coordinates, the image will be centered about its local origin.
The local origin is at the center of the image; the reference point is initialized to this point. This means that once the image is onscreen, any further access to x or y will refer to the center of the image, not to the top/left values optionally specified in display.newImage(). You can override this behavior by specifying a different reference point for the image.
Loading the same image file more than once, as in the code above, does not use additional texture memory, since Corona will automatically re-use the texture data from the first instance of the image.
The default behavior of display.newImage() is to auto-scale large images. This is to conserve texture memory. However, there are times when you do not want to have images auto-scaled, and there is an optional boolean flag in the parameter list to control this manually.
To override autoscaling and show the image at its full-resolution, use the optional isFullResolution parameter. By default, it is false, but if you specify true, then the new image is loaded at its full resolution:
display.newImage( [parentGroup,] filename [, baseDirectory] [, x, y] [,isFullResolution] )
myImage = display.newImage( "image.png", 10, 20, true )
Limitations and known issues:
Dynamic-resolution images are similar to the ordinary images above, except that Corona can automatically substitute higher-resolution assets on higher-resolution devices. This lets you swap in double-resolution images on the iPhone 4, while maintaining your code and layout from the older iPhones. But this feature also lets you handle more complex multi-screen deployment cases, including cases where the screen resolutions of different devices do not fall into a simple 2:1 ratio.
Dynamic image resolution works in conjunction with dynamic content scaling, which is discussed in the "Configuring Projects" section of the API Reference.
Syntax: display.newImageRect( [parentGroup,] filename [, baseDirectory] w, h ), where:
w is the content width of the image, which is the width in the reference screen of the content.h is the content height of the image, which is the height in the reference screen of the content.The actual image chosen will depend on the current content scale determined by Corona, which is the ratio between the current screen and the base content dimensions defined in config.lua. Based on this scale, Corona uses the imageSuffix table (also defined in config.lua), which lists the suffixes for the same family of images, to find the best match from the image choices available. For example, you may define an image suffix of "@2" to indicate 2x resolution images, but you can also choose any other naming suffix and resolution multiplier.
myDynamicImage = display.newImageRect( "baseImage.png", 100, 100 )
It is important to remember that the two numerical values represent the base image size, not the onscreen position of the image. This base size must be defined at load time, so that Corona knows how to render the higher-resolution alternative images.
For a full discussion of how to use this feature, see the documentation on dynamic image resolution in the "Configuring Projects" section.
Shapes in Corona are created using vector objects. Vector objects are a special type of DisplayObject. The following return Lua tables representing rectangle, rounded rectangle, and circle, respectively:
display.newRect( [parentGroup,] left, top, width, height ) creates a width by height rectangle with the top-left corner at (left, top). The local origin is at the center of the rectangle; the reference point is initialized to this local origin. By default, there is no fill or stroke color.
display.newRoundedRect( [parentGroup,] left, top, width, height, cornerRadius ) creates a width by height rounded rectangle with the top-left corner at (left, top). The corners are rounded by quarter circles of radius cornerRadius. The local origin is at the center of the rectangle; the reference point is initialized to this local origin. By default, there is no fill or stroke color.
display.newCircle( [parentGroup,] xCenter, yCenter, radius ) creates a circle with radius radius centered at (xCenter, yCenter). The local origin is at the center of the circle; the reference point is initialized to this local origin. By default, there is no fill or stroke color.
object.strokeWidth sets the stroke width in pixels. Note that stroke widths are broken up to inner and outer parts. The stroke is centered on the boundaries of the object, but when the stroke width is odd, Corona does an integer divide by 2 (e.g. 3 / 2 = 1; 1 / 2 = 0) and set the inner width to that; the remainder is the outer width. This avoids blurring around the edges of the stroke. For example, a stroke width of 3 results in an inner width of 1 and an outer width of 2.
One specific consequence is that if a rectangle fills the screen, a stroke width of 1 will be drawn entirely offscreen. Also, adding a stroke increases the width and height of the object by twice the amount of the outer stroke.
object:setFillColor( r, g, b [, a] ) All components must be between 0 and 255. Alpha is optional and is 255 (opaque) by default.
object:setStrokeColor( r, g, b [, a] ) All components must be between 0 and 255. Alpha is optional and is 255 (opaque) by default.
The Polylines API draws connected line segments, with any color and stroke width, using the Corona vector engine. The resulting object is a standard Corona display object, and can be independently moved and scaled like any other display object. The stroke and color properties can also be changed after the object has been drawn.
Polylines are a series of vertices specifying endpoints of line segments. The lines have a stroke width, specified in a "width" parameter. Currently, multiple line segments have miter joins. In other words, an angle joint comes to a point, as opposed to being rounded. The start and end have butt caps.
The current Polyline API is as follows:
local a = display.newLine( [parent,] x1,y1, x2,y2 )
a:setColor( r, g, b, a )
a:append( x, y [,... ] )
a.width = strokeWidth
Code example:
local star = display.newLine( 0,-110, 27,-35 ) star:append( 105,-35, 43,16, 65,90, 0,45, -65,90, -43,15, -105,-35, -27,-35, 0,-110 ) star:setColor( 255, 102, 102, 255 ) star.width = 3
See the Graphics/PolyLines sample code for an animated demo that runs on iPhone and iPad.
display.newText( [parentGroup,] string, x, y, font, size ) creates a text object with its top-left corner at (x, y). The local origin is at the center of the text; the reference point is initialized to this local origin. By default, there is no text color.
The font parameter is a string that names the font. You can obtain an array of available fonts via native.getFontNames() . Alternatively, you can also pass the following constants instead of a string:
object.size is the size of the text
object:setTextColor( r, g, b [, a] ) All components must be between 0 and 255. Alpha is optional and is 255 (opaque) by default.
object.text is a string that contains the text of the textfield. This can be used to update the string value for the text object.
1 2 3 4 5 | local myText = display.newText( "Hello, World", 0, 0, "Helvetica", 16 ) myText:setTextColor(0, 0, 255) --Change the value of myText myText.text = "Hello, Universe!" |
1 2 3 4 5 6 7 8 9 10 11 12 13 | settings = { iphone = { plist = { UIAppFonts = { "Harrowprint.ttf" } }, }, } |
1 | local text = display.newText( "Hello Harrowprint font!", 0, 0, "Harrowprint", 50 ) |
Group objects are a special type of DisplayObject. You can add other display objects as children of a group object. You can also remove them. Even if an object is not visible, it remains in the group object until explicitly removed. Thus, to minimize memory consumption, you should explicitly remove any object that will no longer be used.
All objects are implicitly added to the current stage which itself is a kind of group object. (Currently, there is only one stage in Corona. This stage represents the entire screen.)
The children of group objects are simply other display objects (vector, groups, etc.). They are accessed by integer index. The first child is at index 1.
Lua table library functions such as table.insert and ipairs(table) are incompatible with groups. This also includes getting the size of a group. #table will return the size of table but not a group or any other display object. To get the size of a group (the number of items in the group) use group.numChildren
display.newGroup() creates a group in which you can add and remove child display objects. Initially, there are no children in a group. The local origin is at the parent’s origin; the reference point is initialized to this local origin.
group.numChildren returns the number of children. You access the children by integer index:
local group = display.newGroup() group:insert( rect1 ) -- assume rect1 is an existing display object group:insert( rect2 ) -- assume rect2 is an existing display object for i=1, group.numChildren do local child = group[i] local description = (child.isVisible and "visible") or "not visible" print( "child["..i.."] is " .. description ) end
group:insert( [index,] child, [, resetTransform] ) Inserts child at index into group, shifting up other elements as necessary. The default value index is n+1 where n is the number of children in the group. The resetTransform parameter determines what happens to child’s transform. When false, child’s local position, rotation, and scale properties are preserved, except the local origin is now relative to the new parent group, not its former parent; when true, child’s transform is reset (i.e. the x, y, rotation, xScale, and yScale properties of child are reset to 0, 0, 0, 1, and 1, respectively). The default value for resetTransform is false. An easy way to move an object above its siblings is to re-insert it: object.parent:insert( object ).
That if you insert a display object into one group and then later insert the same object into another group, the display object is removed the original group into which it was inserted. An object can only exist in one group at a time. The following code sample illustrates this:
1 2 3 4 5 6 7 8 9 10 11 | local txt=display.newText('Hello',0,0) local g1=display.newGroup() local g2=display.newGroup() -- Insert text object into g1 g1:insert(txt) -- Insert same text object into g2 g2:insert(txt) print("g1[1]: " .. tostring(g1[1])) -- prints nil print("g2[1]: " .. tostring(g2[1])) -- prints textObject |
group:remove( indexOrChild ) Removes from group the display object specified by indexOrChild, shifting down other elements as needed. The argument indexOrChild is either the index position of the child within group or the child display object itself. In either case, it returns the removed display object.
More information in the Corona Display Groups 101 blog post.
Stage objects are a special type of GroupObject, so all methods and properties of group objects are available in stage objects. Conceptually, the stage is the root group for all display objects and groups. You access the current stage object using display.getCurrentStage().
All objects are implicitly added to the current stage which itself is a kind of group object. (Currently, there is only one stage in Corona. This stage represents the entire screen.)
stage:setFocus( displayObject [, touchID] ) sets displayObject as the target for all future hit events. Pass nil to restore default behavior for hit event dispatches. This is typically used to implement buttons that change appearance when a user initially presses them.
display.captureScreen( saveToAlbum ) captures the contents of the screen and returns it as an image object positioned so that the top-left of the screen is at the origin. If saveToAlbum is true, then it adds the image to your device’s album; on the simulator, it saves to the desktop.
display.getCurrentStage( ) returns a reference to the current stage object, which is the root group for all display objects and groups. Currently, Corona has a single stage instance, so this function always returns a reference to the same object (which represents the entire screen).
display.save( displayObject, filename [, baseDirectory] ) renders the display object referenced by displayObject into a JPEG image and saves it in filename. The display object must currently be in the display hierarchy; otherwise no image is saved. If the display object is a group object, then all children are rendered. The argument baseDirectory is optional. It can be either system.DocumentsDirectory (the default) or system.TemporaryDirectory.
display.setStatusBar( mode ) hides or changes the appearance of the status bar. The argument mode should be one of:
display.contentWidth A read-only property representing the original width of the content in pixels.This will default to the screen width, but may be another value if you are using content scaling in config.lua.
display.contentHeight A read-only property representing the original height of the content in pixels. This will default to the screen height, but may be another value if you are using content scaling in config.lua.
display.viewableContentWidth A read-only property that contains the width of the viewable screen area in pixels, within the coordinate system of the original content. This is useful since depending on which dynamic scaling mode is used, and the aspect ratio of the device used to view the content, some of the original content may be scaled in such a way that portions are off-screen.
display.viewableContentHeight A read-only property that contains the height of the viewable screen area in pixels, within the coordinate system of the original content. This is useful since depending on which dynamic scaling mode is used, and the aspect ratio of the device used to view the content, some of the original content may be scaled in such a way that portions are off-screen.
display.statusBarHeight A read-only property representing the height of the status bar in pixels (only valid on iOS devices).
At the beginning of this section, we described display objects as behaving "similarly" to Lua tables. An exception to this rule is that you cannot set the metatables of display objects. This is due to the nature of our C++/Lua integration in this particular case.
Corona display objects are native C++ objects internally. The way Lua implements binding native pointers is with "userdata", which sets the metatable. Userdata metatables cannot be replaced by Lua code; this is a measure defined by Lua (see Programming in Lua for details).
Normally, native objects bound to Lua in this way do not behave like tables, and there are a number of examples in Corona of this. Such objects may have properties and/or methods, but are not extensible. In contrast, Corona display objects do behave like tables — this is a convenience feature, and the alternative would have been having a field for "user data", allowing you to access your own data associated with a display object. Raising this functionality directly into the display object itself is simpler and more extensible for the end user, which is why this was done this way. So the underlying native bridge is constrained by what is allowed in Lua, and we view this architectural choice as a fundamental design feature of Corona. Ultimately, Corona is a C++/OpenGL engine with frameworks designed for rapid development, and the product's premise is that these advantages justify this use of metatables on the display objects.
@horacebury, how much memory are we talking about if we just remove the group (and, so also its children) but don't go through and set all the variable references to nil? The graphic object is removed, but are we just talking about a few bytes left behind per variable?
None of it is removed because you are holding references to the display objects. Removing the group removes the group object (if you remove it's reference from your variable) but only setting your variables to nil will remove any object's reference from memory.
It is for this reason that when I create a new object which represents something on screen that I create a display group. Then anything associated with it becomes a regular reference on that group's object as well. So, calling removeSelf() on the group, then setting the group's variable reference to nil causes it to be completely unreferenced by the system and therefore completely garbage collected.
@horacebury, so if I put my objects into a group, then later call removeSelf() on the group and set the variable for that group to nil, then all children of that group are fully removed?
I want to make sure I don't need to step through and set the variables for each child of the group to nil as well. I'm not doing that now, and it does seem to be working properly.
You need to know that there are two factors at work here:
Display objects:
The display group contains display objects. removeSelf() on the group will recursively call removeSelf() on all display objects (groups or visible items) until they are all removed from the screen.
Object references:
Any object which is no longer referenced by a variable will be removed from memory. Being referenced means either being in a table (as in a list) or being referred to by a variable (either a dot property on a table or something like a local.)
If you are not referring to display objects (like images) by any variables and you have called removeSelf() on the display object, it will be removed from the screen and memory.
The confusion comes from removeSelf() actually being helpful by removing the display object from it's parent group, but most tend to think (in the beginning) that this will nil out any regular variables. It won't.
Clear as mud?
When you call removeSelf on a display group the display objects which are added to it's group are also removed. This does not mean that your own references are removed so those will still remain and the memory will not be garbage collected until you set every variable reference to a display (or any other) object to nil.