Advertisement
  1. Code
  2. Mobile Development
  3. Corona

Build an Endless Runner Game From Scratch: The Game Menu

Scroll to top
Read Time: 12 min
This post is part of a series called Corona SDK: Build an Endless Runner Game From Scratch.
Build an Endless Runner Game From Scratch: Boss Battles
Build an Endless Runner Game From Scratch: App Store Publishing

Welcome to the latest installment in the Endless Runner series. In today's tutorial, you will learn how to build a game menu using the Director Class. Let's get started!

Congratulations on coming this far in the series! It has been a lengthy run, but now we have a fully functional game and hopefully a basic understanding of how to add your own components to expand on everything. The step we are going to do now is to put our little level into a menu system so it feels like a full game. 

We are going to do this by using the director class, which is an incredibly well made little library by Ricardo Rauber that is going to do all of the work for you. Once you see how laughably easy it is, you will be able to implement this quickly in any project.

The first thing that you need to do is go to here and download the latest version of the class. When you download it, it is going to give you a lot of files. It comes with a lot more than just the director class, including examples, templates, and additional functions that can make your life easier, so feel free to check out everything that it has to offer. If you don't want all of the fun little extras provided, you can simply download the files for this tutorial and grab it from there.

Now that we have the director.lua file, put it in the same folder as your main.lua. Speaking of your main.lua file, go ahead and rename it. It doesn't matter what you change it to because we are going to end up deleting it anyway. After you have done this you are going to make three new files in that folder. Call them main.lua, menu.lua, and game.lua. The basics of how this is going to work is that main.lua is going to get called to start the game. It is going to be the base of our program, while menu.lua and game.lua are going to act as components(displayGroups) that are displayed within a displayGroup inside of the main.lua itself, much the same way all of the different displays groups in our game are all held and displayed from within the screen displayGroup in our current game.

So, first things first, let's set up our new main.lua file. Open it up and plop this code in there:

1
2
display.setStatusBar(display.HiddenStatusBar)
3
--by telling Corona to require "director" we are
4
--telling it to include everything in that file,
5
--giving us easy access to its functions. This is
6
--also how you would include any functions or
7
--"classes" that you created in outside files.
8
local director = require("director")
9
local mainGroup = display.newGroup()
10
local main = function()
11
     --this creates a view that we will use to load
12
     --the other scenes into, so as our game progresses
13
     --technically we are staying in the main.lua file
14
     --and just loading new views or scenes into it
15
     mainGroup:insert(director.directorView)
16
     --we tell the director to load the first scene which
17
     --is going to be the menu
18
     director:changeScene("menu")
19
end
20
--be sure to actually call the main function
21
main()

So that is it! Take away the comments and you will see it only takes about 5 lines to get the director class up and running. As it says in the comments, the way this is actually working is main.lua gets started first, but then instead of having the flow of the game be dictated inside of the main.lua file, we let the director class take over. We create a display.newGroup and reserve it as our main view. So when the game actually loads up, everything that you see is actually being viewed from the main.lua file inside of this display group. Pretty neat, huh! So, once you insert that view into it, we simply need to tell the director which scene to load up and it will automatically take us there. Easy enough, right?

The next thing that we need to do for this to actually work is to have a menu scene. The code is really simple and most of it we have already seen, so I'm going to post the whole file first and then explain the few things that are new. Let's open up menu.lua and see how easy it is to actually create a simple menu system. Copy the following into your menu.lua:

1
2
--this line is required so that director knows that
3
--this is a scene that can be loaded into its view
4
module(..., package.seeall)
5
--we need to be able to access the director class of
6
--course so be sure to include this here
7
local director = require("director")
8
local sprite = require("sprite")
9
--everything that you want this scene to do should be
10
--included in the new function. Everytime the director
11
--loads a new scene it will look here to figure out what
12
--to load up.
13
new = function( params )
14
     --this function will be returned to the director
15
     local menuDisplay = display.newGroup()
16
     --everything from here down to the return line is what makes
17
     --up the scene so... go crazy
18
     local background = display.newImage("background.png")
19
     background.x = 240
20
     background.y = 160
21
     local spriteSheet = sprite.newSpriteSheet("monsterSpriteSheet.png", 100, 100)
22
     local monsterSet = sprite.newSpriteSet(spriteSheet, 1, 7)
23
     sprite.add(monsterSet, "running", 1, 6, 600, 0)
24
     local monster = sprite.newSprite(monsterSet)
25
     monster:prepare("running")
26
     monster:play()
27
     monster.x = 60
28
     monster.y = 200
29
     local monster2 = sprite.newSprite(monsterSet)
30
     monster2:prepare("running")
31
     monster2:play()
32
     monster2.x = 420
33
     monster2.y = 200
34
     monster2.xScale = monster2.xScale * -1
35
     local title = display.newImage("title.png")
36
     title.x = 240
37
     title.y = 80
38
     local playButton = display.newImage("playButton.png")
39
     playButton.x = 240
40
     playButton.y = 220
41
     menuDisplay:insert(background)
42
     menuDisplay:insert(monster)
43
     menuDisplay:insert(monster2)
44
     menuDisplay:insert(title)
45
     menuDisplay:insert(playButton)
46
     --this is what gets called when playButton gets touched
47
     --the only thing that is does is call the transition
48
     --from this scene to the game scene, "downFlip" is the
49
     --name of the transition that the director uses
50
     local function buttonListener( event )
51
          director:changeScene( "game", "downFlip" )
52
          return true
53
     end
54
     --this is a little bit different way to detect touch, but it works
55
     --well for buttons. Simply add the eventListener to the display object
56
     --that is the button send the event "touch", which will call the function
57
     --buttonListener everytime the displayObject is touched.
58
     playButton:addEventListener("touch", buttonListener )
59
     --return the display group at the end
60
     return menuDisplay
61
end

One thing that is new here is the director:changeScene() line. It's pretty straight forward as it does exactly what you would think it would. However, I wanted to point out the secondparameter, the "downFlip". There are a lot of built in transitions that can make your game look all fancy when switching between scenes, it just depends on what you want your game to look like. Here is an image of our transition in progress.

TransitionTransitionTransition

Be sure to try out some of the different transitions to find the one that will work best for your game. You can find a full list of them in the director.lua file. Just look at all of the different effects and give them a whirl. A couple more examples you can try quickly if you don't want to go digging are "crossfade", "overfromtop", and "flipFromBottom" to name just a few! So, aside from that, there is very little in there that you haven't seen before. All of that stuff is just making a cheap little main menu screen. There are a couple things in there that you should take note of that will be required in every scene that the director needs. The first being:

1
2
module(..., package.seeall)

Plain and simple. You need that exact line at the top of every *.lua file that the director is going to use as a scene. After this you have the new() function that is called when entering the scene and everything that you want the scene to do should be included here. The first thing you need to do is make a displayObject that will be returned to the director to be displayed, then just make sure to return it at the end of the new function. That is all. Sound easy? That's because it is! The director class really makes it that easy. As long as your images are in the right spot for the menu scene you should be able to run the main.lua file and have it start up without any problems.

So far we have our main file and our main menu file taken care of. The last thing that we need to do is make some changes to our game file. This is also going to be easy. Open up the game.lua file and add the following code:

1
2
module(..., package.seeall)
3
local director = require("director")
4
new = function( params )
5
	local gameDisplay = display.newGroup()
6
	--paste code here
7
	return gameDisplay
8
end

That is the barebones of what you need for a scene. Incidentally, this is all you need to get your old main.lua file into your game.lua file. Once you have that in there, the only thing you have to do is copy your entire old main.lua file and paste it where it says paste code here. Do that and you are done. . .almost. We are also going to make some changes to how we display our game over message. Rather than having one large button, we are going to break it up into several smaller buttons that let us choose to restart the game or go back to the menu. Let's start making some of those changes (note that gameOver.png was changed to fit the new buttons layout. The dimensions of the image is still the same so you shouldn't have to make any other adjustments to it). The first changes are going to be to add the new buttons in the game.

Add this code to where we add all the other images at the top of the file:

1
2
local yesButton = display.newImage("yesButton.png")
3
yesButton.x = 100
4
yesButton.y = 600
5
local noButton = display.newImage("noButton.png")
6
noButton.x = 100
7
noButton.y = 600

Then be sure to add them both to the screen as well. Add these after the rest of the screen inserts so they appear on top of everything else:

1
2
screen:insert(yesButton)
3
screen:insert(noButton)

The next thing you will want to do is go to the touched() function and remove the first if/else statement so that it looks like this:

1
2
function touched( event )
3
if(monster.isAlive == true) then
4
	if(event.phase == "began") then
5
		if(event.x < 241) then
6
			if(onGround) then
7
				monster.accel = monster.accel + 20
8
			end
9
			else
10
				for a=1, blasts.numChildren, 1 do
11
					if(blasts[a].isAlive == false) then
12
						blasts[a].isAlive = true
13
						blasts[a].x = monster.x + 50
14
						blasts[a].y = monster.y
15
						break
16
					end
17
				end
18
			end
19
		end
20
	  end
21
     end

By doing this it makes the touched function one that purely handles in-game interactions. We are going to move the logic that restarts the game to its own function. Add these functions below the touched() function:

1
2
function noListener(event)
3
	director:changeScene( "menu", "downFlip" )
4
	return true
5
end
6
function yesListener(event)
7
	restartGame()
8
	return true
9
end

So, pretty straight forward, and the same thing that we have done several times now. Next, shoot down to the bottom of the code where we add our event listeners and add two more listeners:

1
2
yesButton:addEventListener("touch", yesListener )
3
noButton:addEventListener("touch", noListener )

So, the last few things we have to do is account for the changes in position to the two buttons when our monster dies, and when we reset the game. Here are the additions we need to include to make sure they work correctly. In the restartGame() function add this:

1
2
noButton.x = 100
3
noButton.y = 600
4
yesButton.x = 100
5
yesButton.y = 600

Then go to the checkCollisions() function, where you should see these lines several times:

1
2
gameOver.x = display.contentWidth*.65
3
gameOver.y = display.contentHeight/2

Add this block right under each instance of that (it should be 4 all in all, one for each way to die):

1
2
yesButton.x = display.contentWidth*.65 - 80
3
yesButton.y = display.contentHeight/2 + 40
4
noButton.x = display.contentWidth*.65 + 80
5
noButton.y = display.contentHeight/2 + 40

Once you have all of those changes in place you should be able to start the game from main.lua and be able to move from your main menu to your game, die, and then choose whether you want to play again or to go back to the menu. So, assuming all is well, that is the end, we now have our game moved into a menu system using the director class! We moved very quickly through most of that, the reason being is that there really wasn't very much new content. If you have any problems with any of the steps, let me know in the comments and I will be more than happy to help you work through them. The new folder in the downloadable file also contains the finished product as well so you can always use that as a reference. Hopefully this tutorial series has been beneficial for you in geting you started in game development with the Corona SDK, as you can see the process overall is really very simple. The Corona SDK is powerful and very user friendly once you get the basics down. Hopefully, you can now move forward and make some awesome games. 

There will be one more tutorial for this series, but it will not be changing the game in anyway, but will be focusing on submitting your game to the app store as that is always an adventure doing it your first time. So happy coding and thanks for following along!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.