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

In Part One of this tutorial we created the world scene together with a player moving on it. Now we are going to make the battle scene, where the player units will fight the enemies.

Learning Goals

  • Scene management in Phaser 3
  • Processing keyboard input to navigate through the user interface
  • Using custom events
  • Inheriting Phaser 3 classes
  • Creating basic Battle Scene logic
  • Use timers

Source code

You can download the files for tutorial here.

Assets

All assets used in this tutorial are CC0 licensed. You can download them from here:
Player characters – https://opengameart.org/content/rpg-character-sprites
Enemies – https://opengameart.org/content/dragon-1

Creating the Scenes

We will start with an empty game and later on we will merge it with the code from part one. Two Scenes will do all the work – BattleScene, where the players will fight and UIScene for the interface.

In the above code, the most interesting part is in the BattleScene create method. Here we don’t use scene.start, but scene.launch to run the UIScene.
When you run the game now, you won’t see anything special, but keep in mind that both scenes are active at the same time. To visualize that better I will add a graphics object to UI Scene and will draw a simple background for the interface.

First add this row to BattleScene create method:

This is a simple trick to make the scene background green without adding an actual image for it. Now add this code to the UIScene create method:

When you run the game now, you should see the green background of the BattleScene and the three blue rectangles of the UIScene:

Now we need to create a concept for the units – both enemies and player heroes. I will create the base class Unit like this:
Add this code somewhere outside the Scenes code, for example at the top of the project:

And now we will create the Enemy like this:

And the Player:

As I am a bit lazy, I will use this spritesheet without the characters looking left. To make them turn left in game I will use the property flipX of Phaser3 Sprite.

For our first battle I will hardcode both the player heroes and the enemy dragons. In the next part of this tutorial we will create them according to the game flow.
Change the BattleScene create method to this:

Now when you run the game, you should see something like this:

Its time to add the user interface. We will have three menus – Heroes Menu, Enemies Menu and Actions Menu. All of them will inherit common Menu class. The Menu class will be a container for MenuItem objects and I will use Phaser.GameObjects.Container as its base class.

Lets start with the MenuItem class. It will extend Phaser.GameObjects.Text andit will have only two methods – select and deselect. The first one will turn the text yellow and the second will return it to white.

Now we need to create the Menu class. It will be a bit more complex. It needs methods to be selected and deselected as a whole (for example when the player need to choose an enemy to attack, the whole Enemies menu is selected). It also needs methods to add menu items.

Now we will create all separate menus:

And now we need to add the menus to the UIScene. Add this code at the bottom of the UIScene create method:

Now you will see that only the actions menu has something in it (because we hardcoded the action Attack). HeroesMenu and EnemiesMenu both are empty. We need to get the data for them from the BattleScene. To access the BattleScene from the UIScene we need to add the following code to its create method:

First I will change the Menu. I will add functionality to clear all MenuItems from it and then add new. First metthod will be called clear and will remove all menu items from the menuItems array. The second will receive an array of units and will add them as MenuItems through addMenuItem. Add this two methods to the Menu class:

And we need methods to call this functions for the menus. Add this code to the UIScene:

And we need to call this functions. Add this at the end of the UIScene create method:

Now your game should look like this:

But our game is way too idle. We need to make it move. The next thing on our list is to handle the user input. A player will move through the menu with the arrow keys and will select an item on the menu by pressing space.
To listen for keyboard events, add this row at the bottom of UIScene create method:

And now we need to add onKeyInput to UIScene:

We will have an active menu, and all commands will be executed on it (currentMenu). So lets write the body of onKeyInput like this:

Its time to implement the turns. For now we will use an array with all units in the BattleScene. We will keep the index of the currently active unit and if it is a player, it will wait on user input, else the game will pick random player hero and the enemy will attack it.

Add this row at the end of BattleScene create method:

This index will show us the currently active unit in the units array. Now we need the nextTurn function. Add this code to BattleScene:

Here we send the custom event “PlayerSelect”. We will wait for it in UIScene.
The other interesting part here is after the enemy’s unit turn we use a timed event to call nextTurn with 3 seconds delay. This way we will have the time to see what is going on on the screen.

In Phaser3 you can listen for events from one Scene on another Scene. Add this row at the bottom of UIScene create method to listen for ‘PlayerSelect’:

And then we need to create UIScene onPlayerSelect method.

Its relatively simple logic, we select the id-th element from the heroesMenu. Then we select the first element in the actionsMenu and it becomes the currently active menu. Now we need to add confirm methods to the menus. The user will interact with the actions menu first, then he will confirm his selection with spacebar and then he should choose an enemy to perform the action (attack) on. When an enemy is selected, we need to inform the BattleScene.

Now change the ActionsMenu to this:

On confirm we will send custom event ‘SelectEnemies’. Now add this to the end of the UIScene create method:

And now we need to create the UIScene onSelectEnemies method:

Its relatively simple, we just make the enemiesMenu active and we select the first enemy.

Now change the confirm method of EnemiesMenu to this:

And then add this row at the bottom of UIScene create method:

And the onEnemy method will deselect all menus and then will send data to the BattleScene:

We are almost ready. We will start the first turn from the UIScene create method. This way we will have both scenes ready before starting the fight. Add this row to the bottom of UIScene create method:

You can play a bit with the game and you can see that the player selection is not received by the BattleScene.
Add this method to BattleScene:

Here we get an action and a target. We use the currently active unit to attack the target. Then we used a timer event to call the next turn.
Now the game is playable but it needs messages to inform the player what is going on. Here is a simple Message class, that you can use:

I will add the message object to the UIScene as it is part of the interface. Add this to the UIScene create method:

And with this our second part of the tutorial is finished.

Published by

Lyubomira Popova

Lyubomira is a developer and entrepreneur. Founder of Tiger Studio, starting game development company. Lyubomira has more than ten years experience developing commercial software and three years making games with Phaser.

Share this article

Leave a Reply

avatar