Images, Shapes, and Text

About Display Objects

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:

Common Properties

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.

Common Object Methods

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:

  • display.CenterReferencePoint
  • display.TopLeftReferencePoint
  • display.TopCenterReferencePoint
  • display.TopRightReferencePoint
  • display.CenterRightReferencePoint
  • display.BottomRightReferencePoint
  • display.BottomCenterReferencePoint
  • display.BottomLeftReferencePoint
  • display.CenterLeftReferencePoint

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.

Images

Bitmap image objects are a type of DisplayObject.

Loading an Image

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.

Image Autoscaling

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:

  • Indexed PNG image files are not supported.
  • Greyscale images are currently not supported; images must be RGB.
  • Images will still be autoscaled if they are larger than the maximum possible texture dimensions of the device. This is usually 1024x1024 (iPhone 3G) or 2048x2048 (iPhone 3GS, iPad).
  • If you reload the same image multiple times, the subsequent calls to display.newImage ignore the isFullResolution parameter and take on the value passed the first time. In other words, the way you load an image file the first time affects the auto-scaling setting the next time you load that same file. This is because Corona conserves texture memory by automatically re-using a texture that has already been loaded. As a result, you can use the same images as many times as you want without consuming additional texture memory.

Images with Dynamic Resolution

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.

Loading an Dynamic Resoultion Image

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.

Creating Shapes

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.

Setting the Stroke Width, Fill Color and 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.

Polylines

display.newLine( )
Polylines

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.

Text

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:

  • native.systemFont
  • native.systemFontBold

Setting Text Size, Color, and String Value

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!"

Using a custom font

You can embed a font in your app. Include the font file in your project directory. You must have the legal right to embed the font. For iOS, you must register the font using the UIAppFonts plist entry. This will only work with iOS 3.2 and higher, and Android versions 1.6 and higher. (The Harrowprint font used in this example can be found here). The plist entry includes the font's extension, and is included in the build.settings file. No build.settings entry is required on Android. Additionally, you can read this tutorial for a walk-through on how to use custom fonts in Corona.
1
2
3
4
5
6
7
8
9
10
11
12
13
settings =
{
        iphone =
        {
                plist =
                {
                        UIAppFonts = 
                        {
                                "Harrowprint.ttf"
                        }
                },
        },
}
Then, refer to the font when creating the text object. IMPORTANT: (1) You must use the name of the font as returned by native.getFontNames(), not the file name. (2) The font name must be spelled EXACTLY right or it won't be used. (3) For a given font file, the font name on Android may be different from the one on iOS.
1
local text = display.newText( "Hello Harrowprint font!", 0, 0, "Harrowprint", 50 )

Groups

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.

Note

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

Creating groups

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.

Getting the Number of Children in a Group (Size)

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   

Inserting and Removing Objects in a Group

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 ).

Note

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

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.)

Setting Focus

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.

Other Display Functions

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.HiddenStatusBar
  • display.DefaultStatusBar
  • display.TranslucentStatusBar
  • display.DarkStatusBar

Content Size Properties

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).

Display Objects vs. Tables: A Technical Discussion

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.

Replies

Viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
horacebury's picture
horacebury
User offline. Last seen 2 hours 20 min ago. Offline
Joined: 17 Aug 2010

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.

DavidBFox's picture
DavidBFox
User offline. Last seen 2 weeks 4 days ago. Offline
Joined: 10 Oct 2010

@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?

horacebury's picture
horacebury
User offline. Last seen 2 hours 20 min ago. Offline
Joined: 17 Aug 2010

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.

DavidBFox's picture
DavidBFox
User offline. Last seen 2 weeks 4 days ago. Offline
Joined: 10 Oct 2010

@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.

horacebury's picture
horacebury
User offline. Last seen 2 hours 20 min ago. Offline
Joined: 17 Aug 2010

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?