Does your game have a main menu with options that can be selected using the keyboard arrow keys or a controller's D-pad?
Maybe it is something inspired by Final Fantasy, Harvest Moon, or Super Mario Bros?
Great choice! They are tried and true UI mechanics but perhaps you are unsure of how to move a selection cursor to the correct button or know which button is then selected? 🤔
If that's the case then this article is what you're looking for! We'll show you how to create a menu like this 👇 for any number of items.
Example Set-Up
This example will consist of one Scene that loads a button image and a cursor hand image. Both images are from Kenney's UI Pack: Space Expansion.
The code will be in TypeScript although it will be very light on types. You can easily convert it to modern JavaScript by removing all the type information.
But if you would like to learn more about making games in Phaser 3 and TypeScript then we have a great, free book to help you get started!
Learn to make an Infinite Runner in Phaser 3 with TypeScript!
Drop your email into the box below to get this free 90+ page book and join our newsletter.
Here's what our barebones Scene looks like:
|
|
We create a cursors
class property to store an instance of CursorKeys
for simple access to the up
, down
, and space
keys. They will be used to move our selection up and down as well as confirm the selection.
The create()
method is where we will create the menu buttons. The 3 other methods will handle selecting the appropriate menu items.
Notice that we use selectNextButton()
in the update()
method when up
or down
is pressed. This is where our logic for moving to the next button will go.
Lastly, the confirmSelection()
method is called when the space
key is pressed for taking an action associated with the selected button.
Creating Menu Buttons
We'll create 3 buttons in a vertical layout for Play, Settings, and Credits.
Each button will consist of an Image
with a Text
object layered on top of it.
|
|
Now that we have 3 buttons, we can keep track of where a selection cursor should go by storing the buttons in an Array and keeping track of which index is currently selected.
Let's do that by creating two new class property called buttons
and selectedButtonIndex
:
|
|
Then in create()
we can add the 3 buttons to the buttons
Array like this:
|
|
Lastly, we can add the hand cursor to the Scene and store a reference to it in a class property called buttonSelector
:
|
|
We use a class property to store a reference to the hand cursor so that we can adjust its x
and y
position in selectButton(index)
.
Selecting a Button
Now that we've created the menu we can implement the selectButton(index)
method to move the buttonSelector
and tint the selected button.
|
|
This method will retrieve the Image
from the this.buttons
Array using the passed in index
and set it as the newly selected button.
It unselects the currently selected button by setting the tint back to white.
Then it gives the newly selected button a green tint and moves the buttonSelector
to be over the right edge of the button.
Lastly, it sets this.selectedButtonIndex
to the passed in index
value.
Add a call to this.selectButton(0)
in the create()
method to start the menu with the first option selected:
|
|
Selecting the Next Button
With the selectButton(index)
method implemented, selecting the next button up or down is as simple as passing in an index
value that is -1
or +1
from what selectedButtonIndex
is.
Here's what selectNextButton(change)
should look like:
|
|
The bulk of the code in this method just wraps the index
value to 0
if it exceeds the length of the array or to this.buttons.length - 1
if it goes under zero. This will keep index
within the bounds of the Array.
Remember that selectNextButton()
is called by the update()
method when the up
or down
keys are pressed.
Passing in -1
will result in selecting the button above the current one and 1
will result in selecting the button below.
This menu is almost completely functional! The last thing is to confirm the selection.
Confirming a Selection
Buttons are usually activated by a mouse click or a touch. How would we do it using the space
key? 🤔
We can use the EventEmitter
instance that exists on every GameObject
. You may have used something like .on('click', this.handler)
with a Sprite
or Image
before.
We can do something similar to that by emitting a different event name in confirmSelection()
:
|
|
Then to use the 'selected'
event we just need to listen to it after we create each button like this:
|
|
Now, when you press space
the selected button will get an event named 'selected'
and the handler will get called.
You can replace the example console.log()
with more appropriate logic like going to a different Scene.
One final thing to remember is that each .on()
should have a matching .off()
to ensure that events are cleaned up. Something like this:
|
|
Next Steps
This seemingly simple menu selection mechanic took quite a bit of explaining!
You can extend this with as many buttons as you need and use it anywhere you have a selection menu. Perhaps in a dialogue box that asks for player input? 🧐
For cases where the location of the selection cursor on each button can be different, store an offset with each button reference instead of just the button in the buttons
Array.
Be sure to sign up for our newsletter so you don't miss any future Phaser 3 game development tips and techniques!
Drop your email into the box below.
Don't miss any Phaser 3 game development content
Subscribers get exclusive tips & techniques not found on the blog!
Join our newsletter. It's free. We don't spam. Spamming is for jerks.