Today I’m going to talk about the most common user interface item for mobile devices – The Button. Okay… do I really need to talk about something as basic as a button? Well, maybe not.. but when I was coding up my first game I came across a few important features that I wanted my custom designed graphical buttons to have, such as –
- When the user touches down on the button, I wanted some type of feedback (larger, smaller, colour change, etc) for the user
- If the user touches down, but intentionally or un-intentionally slides outside of the bounds of the button – the action of the button does not continue
Sounds simple right?
I will describe the options available and the implementation of each using one of my favourite tools for creating 2D games: Corona SDK.
The language we will use here is: Lua.
If you don’t know Lua, don’t worry, if you have had any exposure to programming languages you’ll pick it up quite quickly. For an run-down on the language check out Corona’s Introduction to Lua page. For a more in-depth look at the language check out http://www.lua.org.
If you haven’t installed Corona yet, go ahead and head over to https://coronalabs.com. Click on the “Download” button in the top right hand side of the page. You will need to register, accept the terms/conditions and you’ll be able to download the SDK for either Windows or Mac. I recommend you check out “Corona SDK System Requirements” and “Installing Corona SDK” for your O/S within Corona University.
Use or choose your favourite text editor, I will be using Sublime Text 3 since Corona has their plugin “Corona Editor” available with Sublime Text.
If you want a guided tour of the installation process, check out this video –
Button Hit Events
Two basic ways to create a Button in Corona SDK include –
- Create a Display Object for your button image (such as PNG file); or
- Create a button using the Widget Library
With display objects like a button in Corona SDK, to make them interactive you must assign what is called an “Event Listener” to the display object. We use the term “display object” here to mean a simple graphical button such as a round button PNG image with a 120 pixel by 120 pixel image area. In a future tutorial, I will show you how to make nice looking graphical buttons and art assets using a free open source vector art program.
If you use the Widget Library to make a button in Corona SDK, you can still use a custom image (non-round) along with built-in themes to mimic the style of an iOS or Android button. The advantage of using the Widget Library is that you don’t specifically need to attach an Event Listener to that object, the act of creating the button via the widget.newButton() function automatically handles the Event Listener attachment. However, with a button created with the Widget Library you can only customise the button using the table parameters available with widget.newButton().
Graphical Button with a Touch Event Listener
Since we are not concerned with the look of our button quite yet, we will create a simple shape to represent the button. Since we will be creating a Display Object and then attaching a Touch event listener to that object, we need to understand that there are four (4) event phases or “states” that the button can have when touched –
"began"
— indicates that a touch has started on the screen"moved"
— indicates that a touch has moved on the screen."ended"
— indicates that a touch has been lifted from the screen."cancelled"
— indicates that the system cancelled tracking of the touch (not to be confused with"ended"
).
Open up Corona SDK, and create a New Project –
When the New Project windows comes up –
- For Application Name: Call it something like “Basic Buttons”
- For Project Folder: Select a location on your computer where you want to store the project (or leave it as the default location)
- For Project Template: Leave the radio button selected as “Blank”
- Leave the Upright Screen Size to “Phone Preset”
- Leave the Default Orientation radio button as “Upright”
Hit the OK button in the New Project window above and the window for your new project should launch (otherwise just navigate to the Project Folder location, like that shown in the New Project window above) –
Take particular note of the two files that I have highlighted in the above project folder view:
- config.lua
- main.lua
Although I will not go into all the configuration details here, we will change part of the “config.lua” file to handle multiple screen sizes and resolutions using the Simple Content Scaling methodology. Corona introduced an alternative called the Adaptive Content Scaling methodology near the end of 2014. We will assume for this simple example that the demo app is used in Portrait model only, with Letterbox type scaling. From the original post on modernizing the “config.lua” file, open the “config.lua” file in Sublime Text (or whatever text editor you use) and ensure the content of this file in your project folder has the following settings –
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
--calculate the aspect ratio of the device: local aspectRatio = display.pixelHeight / display.pixelWidth application = { content = { --graphicsCompatibility = 1, -- This turns on Graphics 1.0 Compatibility mode width = aspectRatio > 1.5 and 640 or math.ceil( 960 / aspectRatio ), height = aspectRatio < 1.5 and 960 or math.ceil( 640 * aspectRatio ), scale = "letterbox", fps = 30, imageSuffix = { ["@2x"] = 1.5, ["@4x"] = 3.0, }, }, } |
Save the “config.lua” file.
In this simple demo, we will only be experimenting with a single page application. Corona handles multi-screen applications (which most real apps have) and the interconnectivity of these screens in your game or app with the Composer library. For now, just know that it exists… as we won’t deal with Composer in this demo.
Open up “main.lua” in Sublime Text (or whatever text editor you use), add the following lines of code –
1 2 3 4 5 6 7 8 9 10 11 12 |
-- main.lua -- Your code here -- Common Helper Variables -- contW = display.contentWidth contH = display.contentHeight centerX = display.contentCenterX centerY = display.contentCenterY -- Create a basic button and position in the center of the screen local myButton = display.newCircle( 100, 100, 60 ) -- Set the button at position x=100, y = 100 myButton:setFillColor(1,0,0) -- Set the fill color to Red (These are normalized R,G,B values) |
Next, launch the Corona Simulator from within Sublime Text (if using it) by hitting Windows Key + F10 (On Windows), CMD + F10 (On Mac), or just navigate to the Corona Editor plugin menu as shown below –
If you are not using Sublime Text, simply go to the Corona SDK front-end GUI and select Open (shown below) –
Then navigate to the “main.lua” file within your project directory. Next you should see the Corona Simulator launch with your button (or Red dot) on the screen at a location of 100 pixels (rightward) on the global content x-axis and 100 pixels on the global content y-axis (downward). Unlike, a standard 2-dimensional Cartesian co-ordinate axis that we learn about in school where the x-axis points to the right and the y-axis points directly upward, Corona SDK (and many mobile devices for that matter) has the global content co-ordinate frame located in the top left hand corner of the screen, with the positive directions of the x-axis and y-axis as shown below –
Next, we’ll reposition the button to the center of the screen and add a Touch event Listener (“main.lua” should now look like this) –
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
----------------------------------------------------------------------------------------- -- -- main.lua -- ----------------------------------------------------------------------------------------- -- Your code here -- Common Helper Variables -- contW = display.contentWidth contH = display.contentHeight centerX = display.contentCenterX centerY = display.contentCenterY -- Create a basic button in corona sdk and position in the center of the screen local myButton = display.newCircle( 100, 100, 60 ) -- Set the button at position x=100, y = 100 myButton:setFillColor(1,0,0) -- Set the fill color to Red (These are normalized R,G,B values) -- Reposition the Button to the center of the screen myButton.x = centerX myButton.y = centerY -- Create the touch event handler function local function myButtonHandler( event ) -- body end -- Add a touch event handler to myButton myButton:addEventListener("touch", myButtonHandler) |
If you re-launch the Corona Simulator (as we did above from Sublime Text or the Corona GUI), the button (or Red dot) is now positioned in the center of the screen, you can touch it, but nothing happens.
Next, we need to fill in some details for the myButtonHandler function. Initially for this we will simply create a text object area near the top of the screen that we will use to show the active “phase” or “state” of the touch when you click the button.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
----------------------------------------------------------------------------------------- -- -- main.lua -- ----------------------------------------------------------------------------------------- -- Your code here -- Common Helper Variables -- contW = display.contentWidth contH = display.contentHeight centerX = display.contentCenterX centerY = display.contentCenterY -- Create a basic button in corona sdk and position in the center of the screen local myButton = display.newCircle( 100, 100, 60 ) -- Set the button at position x=100, y = 100 myButton:setFillColor(1,0,0) -- Set the fill color to Red (These are normalized R,G,B values) -- Reposition the Button to the center of the screen myButton.x = centerX myButton.y = centerY -- Add a text box to display the state/phase of the touch event from the button local myText = display.newText( "Hello Button", centerX, 200, native.systemFont, 30 ) myText:setFillColor( 1, 0, 0 ) -- Create the touch event handler function local function myButtonHandler( event ) if (event.phase == "began") then myText.text = "Button Phase is: " .. event.phase elseif (event.phase == "moved") then myText.text = "Button Phase is: " .. event.phase elseif (event.phase == "ended" or event.phase == "cancelled") then myText.text = "Button Phase is: " .. event.phase end return true end -- Add a touch event handler to myButton myButton:addEventListener("touch", myButtonHandler) |
Now when you run the Corona Simulator and click on the button you should get something that looks like this – (Note: The White dot in the video below is my finger touch, as I recorded this on my Android device)
Next, we’ll replace the Red dot button (created using display.newCircle() ) with an actual image file. From the top header in this post well choose the button in the bottom right corner (with the upward arrow) for the button image. The button is a 120px by 120px image, Right Click on the button image below and do as “Save Image As..” to your project folder.
Your “main.lua” file should now looking like the following –
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
----------------------------------------------------------------------------------------- -- -- main.lua -- ----------------------------------------------------------------------------------------- -- Your code here -- Common Helper Variables -- contW = display.contentWidth contH = display.contentHeight centerX = display.contentCenterX centerY = display.contentCenterY -- Replace the basic button in corona sdk with display.newCircle() earlier, with Image file using display.newImageRect() local myButton = display.newImageRect("demo-button.png",120,120) -- Reposition the Button to the center of the screen myButton.x = centerX myButton.y = centerY -- Add a text box to display the state/phase of the touch event from the button local myText = display.newText( "Hello Button", centerX, 200, native.systemFont, 30 ) myText:setFillColor( 1, 0, 0 ) -- Create the touch event handler function local function myButtonHandler( event ) if (event.phase == "began") then myText.text = "Button Phase is: " .. event.phase myButton.xScale = 0.85 -- Scale the button on touch down so user knows its pressed myButton.yScale = 0.85 elseif (event.phase == "moved") then myText.text = "Button Phase is: " .. event.phase elseif (event.phase == "ended" or event.phase == "cancelled") then myText.text = "Button Phase is: " .. event.phase myButton.xScale = 1 -- Re-scale the button on touch release myButton.yScale = 1 end return true end -- Add a touch event handler to myButton myButton:addEventListener("touch", myButtonHandler) |
We replaced the simple circle button on Line 16 with the image button using display.newImageRect(). Also, we added image scaling on Lines 32,33,42 and 43 to give the user feedback that the button has been touched and released. Next, we will add a small rectangular image (to represent a bullet or laser beam) that shoots from the bottom left of the screen to the top left of the screen each time the button is pressed. The bullet will be created using display.newRect().
We’ll also add a sound when the bullet is fired. Download this MP3 titled “Laser1” below, Right-Click on the link and select “Save Link As..” and save the MP3 file to your project folder –
Your “main.lua” file should look like the following –
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
----------------------------------------------------------------------------------------- -- -- main.lua -- ----------------------------------------------------------------------------------------- -- Your code here -- Common Helper Variables -- contW = display.contentWidth contH = display.contentHeight centerX = display.contentCenterX centerY = display.contentCenterY -- Replace the basic button in corona sdk with display.newCircle() earlier, with Image file using display.newImageRect() local myButton = display.newImageRect("demo-button.png",120,120) -- Reposition the Button to the center of the screen myButton.x = centerX myButton.y = centerY -- Add a text box to display the state/phase of the touch event from the button local myText = display.newText( "Hello Button", centerX, 200, native.systemFont, 30 ) myText:setFillColor( 1, 0, 0 ) -- Load the Bullet sound local bulletSound = audio.loadSound( "Laser1.mp3" ) -- Add a function to fire off a bullet each time the myButton is pressed local function fireBullet() local bullet = display.newRect(0,0,8,24); bullet:setFillColor( 0, 1, 0 ) local function freeUp() -- remove the object once the transition to top of sceen completes, free the memory display.remove( bullet ) bullet = nil --set to nil! end bullet.y = contH + bullet.height; audio.play(bulletSound) transition.to(bullet, {time=1000, y = -bullet.height, onComplete=freeUp}) end -- Create the touch event handler function local function myButtonHandler( event ) if (event.phase == "began") then myText.text = "Button Phase is: " .. event.phase myButton.xScale = 0.85 -- Scale the button on touch down so user knows its pressed myButton.yScale = 0.85 fireBullet() elseif (event.phase == "moved") then myText.text = "Button Phase is: " .. event.phase elseif (event.phase == "ended" or event.phase == "cancelled") then myText.text = "Button Phase is: " .. event.phase myButton.xScale = 1 -- Re-scale the button on touch release myButton.yScale = 1 end return true end -- Add a touch event handler to myButton myButton:addEventListener("touch", myButtonHandler) |
Again, when you run the Corona Simulator and click on the button you should get something that looks like this below – (Note: Again.. the White dot in the video below is my finger touch, as I recorded this on my Android device)
However, did you notice something not quite right? Near the end of the video demo above, when I touch down on the button but slide off the button and release, two things happen:
- First I get the ‘began‘ phase, followed by the ‘moved‘ phase as expected… however, I don’t get the “ended” phase on releasing the touch outside of the button bounds (60 pixel radius).
- The button remains scaled to 85% of its original (non-touched) size.. it does not scale back to 100% of its original size on releasing the touch.
To see how to handle the infamous slide off anomaly with a touch event listener described above, I will outline a couple different solutions in Part 2 of this post.
Stay tuned….
Corona Geek #141 - Creating and Matching Puzzle Pieces - Corona Geek - Mobile Development Using Corona SDK
[…] How-to: Create a UI Button in Corona SDK […]
Corona Geek #141 – Creating and Matching Puzzle Pieces | SDK News
[…] How-to: Create a UI Button in Corona SDK […]
rs
“To see how to handle the infamous slide off anomaly with a touch event listener described above, I will outline a couple different solutions in Part 2 of this post.
Stay tuned….”
Great tutorial, spent all morning looking for help on this most alien of app features “the button” Hope you find the time to finish this helpful tutorial soon.
rs
oops found your invisibly tiny link… “button, corona sdk “
Randal
I’m glad you found the tutorial helpful Robert. Looks like you found Part 2 via the “corona sdk” tag. More tutorials (possibly video tutorials) will be coming in the near future. Cheers
Part 2: Create a UI Button in Corona SDK | Dinesh Ram Kali.
[…] the previous Code Basics post on Creating a UI Button in Corona SDK, we worked our way from simply displaying a Red dot button on the screen, to creating a custom UI […]