How to create a Turn-Based RPG in Phaser 3 – Part 3

In Part One of this tutorial we created the WorldScene, and in Part Two we made the BattleScene. If you haven’t read them I strongly recommend for you to do so before continuing. Now, in Part Three, we will combine both scenes into a working game.

Source code

You can download the files for this tutorial here.

Don't miss out! Offer ends in
  • Access all 200+ courses
  • New courses added monthly
  • Cancel anytime
  • Certificates of completion


All assets used in this tutorial are CC0 licensed. The tiles are created by Kenney Vleugels and you can download them at
Player characters –
Enemies –

Scene Switching

At the start, I will try to simplify and explain the scene switching logic. We will use the final version of the WorldScene from the first part of the tutorial and we will create very basic BattleScene and UIScene.

Get your WorldScene working and then edit the config object to add BattleScene and UIScene. Edit it to look like this:

And here are our simplified BattleScene and UIScenes. We will use them to show how the scene switching will work:

Now we need to change the WorldScene to start the BattleScene. Change WorldScene onMeetEnemy like this:

If you run the game now, you will see that, when the player hits an invisible enemy, it starts BattleScene. And BattleScene will control the UIScene. Lets see how to return back to the WorldScene. I will create a BattleScene method exitBattle:

This function will sleep the UIScene (make it not active and not visible) and will switch from BattleScene to WorldScene. For now I will add simple time event that will call this function after 2 seconds.
Add this to the end of BattleScene create method:

Now we have a problem. Everything works only the first time we switch to BattleScene. The second time, its create function is not called so we don’t have UIScene visible and we don’t exit BattleScene after the given time.
To fix this we need to listen to Scene ‘wake’ event. Add this code at the end of BattleScene create function:

We need to add the wake function. It will run the UIScene and will add a timed event to exit the BattleScene:

Now our simple BattleScene should work just fine each time we enter a battle.

Make the game work

Its time to change the BattleScene code to the one from the second part of this tutorial. Remove only its BootScene as we don’t need two boot scenes to load our game. You may need to add the resources of the enemies to the current BootScene loader.

Its time to change the unit class like this:

Here you will see the variable menuItem. We will link each unit to its menu item, and when the unit is dead, it will notify the menu item for this, so the player won’t be able to select a killed enemy.
Also we have new member variable – living. We will use it to check if the current unit is alive. Only living units will be able to participate in battle.

Now we need to edit the next unit attack circle to take in consideration this new property. Change BattleScene nextTurn method to this:

Here we increment the index until we get a living unit. The units that are dead won’t be able to move any more. But now we have a problem. We will have endless cycle if there are no living units. To avoid this, we must check for game over or victory.

Add this code at the top of nextTurn:

And here is how checkEndBattle should look:

And here is endBattle:

The final version of nextTurn:

As we have seen from the simple version of BattleScene we need to listen for the wake event. I’ve created new function startBattle and moved more of the starting logic there. Here is how my startBattle looks:

And here is how the BattleScene create function changes:

Now we will change the MenuItem class like this:

Here you can see the unitKilled method called by the units on dying. This will deactivate and hide the menu item. Now we must change the menu navigation, so when the selection moves up or down, it will skip the deactivated items.
Here is how to change Menu methods moveSelectionUp and moveSelectionDown:

We need to change the select method too, so when the menu is activated, it will select an active item:

This is the moment to mention, that I decided to change the name of the event SelectEnemies to SelectedAction. Also, I changed the listeners to mach the name. You can continue with the old name or use the new one. The best way is to just use replace all and your ide will do everything automatically. As the event is fired when the player have selected an action, I think the code now is a bit more self explanatory.

We need to change the Menu remap method too:

And change Menu addMenuItem to this:

Now we are almost done with the changes. What is left, is to fix the UIScene and the WorldScene to listen for wake event. I will start with the UIScene. The code that is responsible for the global menu creation will stay at its create method, but the code responsible for the specific battle will go to new function. Change UIScene create method to this:

You see now that we call createMenu both when we start the UIScene for the first time and when its started through wake event. Here is our createMenu:

After running the game now you may found a problem. If its player turn, and he press multiple times space when selecting an enemy, nextTurn is called multiple times and you can witness strange behavior. To fix this we must be sure that we send only one event per menu. To do so, I’ve decide to add property selected to the Menu class. When Menu gets focus, this property becomes true. When the player chooses an action, it becomes false and the Menu won’t get its action method called again.
Here is how the Menu class should look at the end:

And here how we will change the UIScene onKeyInput:

Now when you run the game almost everything should run fine. But sometimes when you go back from BattleScene to WorldScene, the character is not waiting patiently but moving in some direction and you need to press and release the key for this direction to stop it. Its small bug, but we have to fix it. We need to wait for WorldScene wake event and then reset the keys.

Add this row to the end of WorldScene create function:

And here is how the wake method should look:

With this we are finished with the third part of the tutorial. Although we have done a lot of work, our game need much more work to be fully functional. Get it as an exercise to save the state of the player characters and to make them get experience and levels. Also you can add more actions to the Actions menu and pass them together with the events.