Menu Structure

I have noticed that several games made with Corona SDK have a Level selection menu with a tile type interface. How exactly do I go about making this sort of thing? There isn’t much documentation about that kind of thing. Any suggestions? [import]uid: 104852 topic_id: 21095 reply_id: 321095[/import]

@chandler767,

I’m not sure if I understand what you mean by tile type interface, but our game has a level select screen where the user can select from 20 levels per page. If this is what you are talking about then I can post some sample code. [import]uid: 16734 topic_id: 21095 reply_id: 83476[/import]

Hi,
I would appreciate it if you shared your sample code.

As for a tiled type of menu this is what I am looking for:
http://www.angrybirds-game-online.com/wp-content/uploads/2011/07/angry-birds-christmas-2.png

-Chandler Mayo [import]uid: 104852 topic_id: 21095 reply_id: 83531[/import]

Hi KenRogoway ,

Yes, I also need level selection/unlock level kind thing, please share some sample code.

Thank you in advance.

[import]uid: 83418 topic_id: 21095 reply_id: 83549[/import]

Doesn’t seem like anything too hard, just use iterators to build the level buttons and storyboard to flip pages?

[code]
local maxLevel = 20 – if you had a table of levels you could use #levels
local xPos = 20
local yPos = 40
local buttonGroup = display.newGroup() – holds all of the buttons

– Iterator time
for i = 1, maxLevel do
– Make the button. This is a fictional function but it would be very easy to make it
local button = makeButton(i)

– Set its position
button.x = xPos
button.y = yPos

– Add it to the display group
buttonGroup:insert(button)

– Increment the xPosition
if i == 5 or i == 10 or i = 15 then
– If it’s a new row, you gotta update xPos and yPos
xPos = 20
yPos = yPos + button.height + 16
else
– Just update xPos
xPos = xPos + button.width + 16
end
end[/code]

Obviously you’d have to fine tune a lot of it, but that’s a fairly simple way to build that sort of visual array. [import]uid: 41884 topic_id: 21095 reply_id: 83550[/import]

Your missing an = sign,

[lua]if (i == 5 or i == 10 or i = 15) then [/lua]

It should be,

[lua]if (i == 5 or i == 10 or i == 15) then [/lua]
-Chandler Mayo [import]uid: 104852 topic_id: 21095 reply_id: 83555[/import]

What can I do with [lua]makeButton(i)[/lua]? I am having some issues getting something to work without an error. [import]uid: 104852 topic_id: 21095 reply_id: 83557[/import]

@KenRogoway I plugged this in and after sorting through a ton of errors I am stumped by this:

Runtime error: /Users/Chandler/Desktop/gfg/main.lua:33: attempt to index global ‘cSceneLevelSelect’ (a nil value)

Its pointing to:
function cSceneLevelSelect:new()

It there a sample project I can download? [import]uid: 104852 topic_id: 21095 reply_id: 83568[/import]

Here is a fully functional Level Select scene for use with Director:

[lua]–***********************************************************************************************–
– cSceneLevelSelect

module(…, package.seeall)

– The max number of levels to show on the screen at a time
NUM_LEVELS_ON_PAGE = 20

local WhatPage = 0

– Main function - MUST return a display.newGroup()
function cSceneLevelSelect:new()
local levelSelectGroup = display.newGroup()
local updateButtons
local menuBtn
local ui = ui
– For check mark to show level is completed
local checkImages = {}

– BACKGROUND IMAGE
local backgroundImage = display.newImageRect( IMAGE_DIR…“SelectLevel.jpg”, display.contentWidth, display.contentHeight )
backgroundImage.x = display.contentCenterX
backgroundImage.y = display.contentCenterY
levelSelectGroup:insert( backgroundImage )

– Go back to the main game menu
local onMenuTouch = function( event )
if event.phase == “release” and menuBtn.isActive then

director:changeScene( “cSceneMainMenu”, “fade” )

end
return true
end

menuBtn = ui.newButton{
defaultSrc = IMAGE_DIR…“menu_menu_up.png”,
defaultX = ScaleX(200),
defaultY = ScaleY(80),
overSrc = IMAGE_DIR…“menu_menu_down.png”,
overX = ScaleX(200),
overY = ScaleY(80),
onEvent = onMenuTouch,
id = “MenuButton”,
text = “”,
font = “Helvetica”,
textColor = { 255, 255, 255, 255 },
size = 16,
emboss = false
}

menuBtn:setReferencePoint( display.CenterReferencePoint )
menuBtn.x = display.contentCenterX
menuBtn.y = display.contentHeight - ScaleY(88)

levelSelectGroup:insert( menuBtn )

local prevBtn

local onPrevTouch = function( event )
if event.phase == “release” and prevBtn.isActive then
if ( WhatPage > 0 ) then
WhatPage = WhatPage - 1
updateButtons()
end
end
return true
end

prevBtn = ui.newButton{
defaultSrc = IMAGE_DIR…“help_arrow_left_up.png”,
defaultX = ScaleX(180),
defaultY = ScaleY(150),
overSrc = IMAGE_DIR…“help_arrow_left_down.png”,
overX = ScaleX(180),
overY = ScaleY(150),
onEvent = onPrevTouch,
id = “PrevButton”,
text = “”,
font = “Helvetica”,
textColor = { 255, 255, 255, 255 },
size = 16,
emboss = false
}

prevBtn:setReferencePoint( display.CenterReferencePoint )
prevBtn.x = ScaleX(136)
prevBtn.y = ScaleY(688)
prevBtn.isVisible = false

levelSelectGroup:insert( prevBtn )

local nextBtn

local onNextTouch = function( event )
if event.phase == “release” and nextBtn.isActive then
WhatPage = WhatPage + 1
updateButtons()
end
return true
end

nextBtn = ui.newButton{
defaultSrc = IMAGE_DIR…“help_arrow_right_up.png”,
defaultX = ScaleX(180),
defaultY = ScaleY(150),
overSrc = IMAGE_DIR…“help_arrow_right_down.png”,
overX = ScaleX(180),
overY = ScaleY(150),
onEvent = onNextTouch,
id = “NextButton”,
text = “”,
font = “Helvetica”,
textColor = { 255, 255, 255, 255 },
size = 16,
emboss = false
}

nextBtn:setReferencePoint( display.CenterReferencePoint )
nextBtn.x = ScaleX(890)
nextBtn.y = ScaleY(688)

levelSelectGroup:insert( nextBtn )

local function onTapTouchGobbler( event )
return true
end

local levelPickBtn = {}

local onLevelPickedTouch = function( event )
if event.phase == “release” then
local levelNum = tonumber(event.id)

if ( levelNum <= MAX_LEVELS ) then
– print( “level “…levelNum…” was selected” )

– You need to set a global here with the level that was picked!

– Reset the count for our ads
director:changeScene( “cSceneGame”, “crossFade” )
end
end
end

for i=1,NUM_LEVELS_ON_PAGE do
levelPickBtn[i] = ui.newButton{
defaultSrc = IMAGE_DIR…“button_level_up.png”,
defaultX = ScaleX( 180 ),
defaultY = ScaleY( 130 ),
overSrc = IMAGE_DIR…“button_level_down.png”,
overX = ScaleX( 180 ),
overY = ScaleY( 130 ),
onEvent = onLevelPickedTouch,
id = string.format( “%d”, i+NUM_LEVELS_ON_PAGE*WhatPage ),
text = string.format( “%d”, i+NUM_LEVELS_ON_PAGE*WhatPage ),
font = “Helvetica”,
textColor = { 0, 0, 0, 255 },
size = ScaleY( 32 ),
emboss = true
}

– If you change NUM_LEVELS_ON_PAGE then you will need to change the next two statements
local nX = 39+191*((i-1)%5)
local nY = 96+130*math.floor((i-1)/5)

levelPickBtn[i]:setReferencePoint( display.TopLeftReferencePoint )
levelPickBtn[i].x = ScaleX( nX )
levelPickBtn[i].y = ScaleY( nY )

levelSelectGroup:insert( levelPickBtn[i] )

checkImages[i] = display.newImageRect( IMAGE_DIR…“CheckMarkYellow.png”, ScaleX(80), ScaleY(80) )
checkImages[i].x = ScaleX( nX + 48 )
checkImages[i].y = ScaleY( nY + 48 )
levelSelectGroup:insert( checkImages[i] )

if ( gWS.bLevelComplete[i] ) then
checkImages[i].isVisible = true
else
checkImages[i].isVisible = false
end
end

function updateButtons()
if ( WhatPage > 0 ) then
prevBtn.isVisible = true
else
prevBtn.isVisible = false
end

if ( ((WhatPage+1)*NUM_LEVELS_ON_PAGE) < MAX_LEVELS ) then
nextBtn.isVisible = true
else
nextBtn.isVisible = false
end

for i=1,NUM_LEVELS_ON_PAGE do
if ( (NUM_LEVELS_ON_PAGE*WhatPage+i) <= MAX_LEVELS ) then
levelPickBtn[i].isVisible = true
levelPickBtn[i]:setText( string.format( “%d”, i+NUM_LEVELS_ON_PAGE*WhatPage ) )
levelPickBtn[i]._id = i+NUM_LEVELS_ON_PAGE*WhatPage

if ( gWS.bLevelComplete[(NUM_LEVELS_ON_PAGE*WhatPage+i)] ) then
checkImages[i].isVisible = true
else
checkImages[i].isVisible = false
end

else
checkImages[i].isVisible = false
levelPickBtn[i].isVisible = false
end
end
end

updateButtons()

clean = function()
end

return levelSelectGroup
end[/lua] [import]uid: 16734 topic_id: 21095 reply_id: 83559[/import]

I’ll put together a sample app. I had just stripped out some items from my actual shipping title. Sorry if there were any errors.

[EDIT]
Here is a fully functional (and tested!) app showing how to do this:

http://www.homebrewsoftware.com/Download/CoronaSDK/HomebrewLevelSelect_v1_00.zip [import]uid: 16734 topic_id: 21095 reply_id: 83570[/import]

Thanks,
I can’t test it right now but later today I will let you know if it works for me. [import]uid: 104852 topic_id: 21095 reply_id: 83578[/import]

Minor revision to display the level selected here:

http://www.homebrewsoftware.com/Download/CoronaSDK/HomebrewLevelSelect_v1_01.zip [import]uid: 16734 topic_id: 21095 reply_id: 83583[/import]

Sounds like Ken has you covered. TBH I’m interested in the bits there myself

makeButton(i) was merely a fictional function; you could theoretically have something like this

[code]local makeButton = function(text)
local button = display.newGroup()
local box = display.newRect(0,0,128,128)
local title = display.newText(text, 0, 0, nil, 20)
title:setReferencePoint(display.CenterReferencePoint)
title.x, title.y = box.x, box.y
button:insert(box)
button:insert(title)

return button
end[/code]

By giving it “i” (which ends up being 1-20) each button gets a title of 1, 2, 3, 4, etc. [import]uid: 41884 topic_id: 21095 reply_id: 83585[/import]

@KenRogoway
Do you know about anyway to make it unlock levels or change the way the images look after their completion? [import]uid: 104852 topic_id: 21095 reply_id: 83610[/import]

Sorry Double Post. [import]uid: 104852 topic_id: 21095 reply_id: 83611[/import]

this is totally untested off the top of my head!

  
local levelsPerRow = 6  
local maxLevels = 30  
local gridX = 1  
local gridY = 1  
local iconHeight = 32  
local iconWidth = 32  
local iconPadding = 16  
local levelButtons = {}  
local currentUnlockedLevel = 5  
  
local gridGroup = display.newGroup()  
local lockedLevel = display.newImageRect("lock.png",iconWidth,iconHeight)  
  
local function gotoLevel(event)  
 local lvl = event.target.name  
 storyboard.gotoScene(string.format("level%02d",lvl))  
 -- director.changeScene(string.format("level%02d",lvl))  
 return true  
end  
  
for i = 1, maxLevels  
 if i \> currentUnlockedLevel then  
 levelButtons[i] = lockedLevel  
 else  
 levelButtons[i] = display.newImageRect(iconImages[i]  
 levelButtons[i].name = i  
 levelButtons[i]:addEventListener("tap",gotoLevel)  
 end  
 levelButtons[i].x = (gridX - 1) \* (iconWidth + iconPadding) + (iconWidth /2 ) -- assuming center reference point  
 levelButtons[i].y = (gridY - 1) \* (iconHeight + iconPadding) + (iconHeight / 2)  
 if i % 6 == 0 then -- end of a row  
 gridX = 1  
 gridY = gridY + 1  
 else  
 gridX = gridX + 1  
 end  
 gridGroup:insert(levelButtons[i])  
end  
gridGroup.x = display.contentWidth / 2  
gridGroup.y = display.contentHeight / 2  
  
-- for storyboard  
group:insert(gridGroup)   
-- or for director  
-- localGroup:insert(gridGroup)  
  

this assumes you have an array of image filenames called iconImages that hold the icons for different levels and an image for your locked out levels.

[import]uid: 19626 topic_id: 21095 reply_id: 83636[/import]

Hi KenRogoway ,

Thank you so much for the Level Select code.

Can I use your code in my Game?

Thanks again.

Mila

[import]uid: 83418 topic_id: 21095 reply_id: 83639[/import]

@chandler767,

Here is a version that shows “locks” on levels. Every time you enter a level it unlocks the next one. Go back to the level select and you will see it has been unlocked.

http://www.homebrewsoftware.com/Download/CoronaSDK/HomebrewLevelSelect_v1_10.zip

@mila.habaer,

Yes, you can use the code in any of your projects. You cannot use the images, as they are just sample images taken from the web. [import]uid: 16734 topic_id: 21095 reply_id: 83647[/import]

Hi KenRogoway ,

Thank you so much for your sample code and kindness.

I have to bother you a question:

I want to do as below:

When Level 1 is selected, the to goto gamelevel1.lua (gamelevel1 is my game for level1), if level 2 is selected, then goto gamelevel2.lua, and so on, how can I do this with your sample code?
Thanks again.

Mila
[import]uid: 83418 topic_id: 21095 reply_id: 84649[/import]

Try this:

[lua] local onLevelPickedTouch = function( event )
if event.phase == “release” then
local levelNum = tonumber(event.id)

if ( levelNum <= MAX_LEVELS and not gWS.bLevelLocked[levelNum] ) then
print( “level “…levelNum…” was selected” )

local whatScene = string.format( “gamelevel%d”, levelNum )

– Reset the count for our ads
director:changeScene( whatScene, “crossFade” )
end
end
end[/lua] [import]uid: 16734 topic_id: 21095 reply_id: 84652[/import]