Create a RPG Battle system with Unity 3D – Part 3 – TurnUnit.cs

In the previous article, we’ve created the turn based battle manager “TurnManager.cs“. The last step is now to create a script that will be attached to an unit. This script will be in charge of starting the turn of the unit.

Unit state

One more time, i will use an enum to handle the unit state. All the explanation is in the as usual :
#region Enum

public enum eTurnUnitState
{
    INACTIVE,       //The unit is not concerned by the battle right now
    IN_BATTLE,      //Currently in the battle
    SLEEPING        //In the battle, but the timer will not affect the unit
}

#endregion

Properties

We don’t need so much properties for the TurnUnit.cs component. Let me explain the properties.
  • timeLeftUntilTurnBegin : This is the time the unit need to wait before it’s turn begins
  • originalTurnTime : This is the original time that the unit need to wait AT THE BEGINNING of the battle. Imagine the unit has a speed up power and we need to recover the original turn time, we need to store it.
  • currentTurnTime : This is the time that the unit will wait for the next turn. If the unit has a speed up power, this is that properties that will be modified.
  • state : the current state of the unit
  • turnNumber : store the turn number if needed
#region Properties

/// 
/// Time left until the unit turn begin
/// 
public float timeLeftUntilTurnBegin;

/// 
/// This is the time the unit need to act.
/// More the action time is high, less the unit will act
/// 
public float originalTurnTime;

/// 
/// current turn time
/// 
public float currentTurnTime;

/// 
/// State of the unit
/// 
public eTurnUnitState state;

/// 
/// current turn number
/// 
public int turnNumber;

#endregion

How to notify the TurnManager.cs that a turn starts or ends ? 

The TurnManager will run its timer once the Init() and Run() function are called. But we need to stop the timer when a turn starts. For this, i will use delegates and events. 

Events and delegate

Using events and delegates will make our turn battle system very powerful and usable easely with external components. (I used delegates and not UnityAction. But feel free to replace it with UnityAction if you want)

Delegate

Simple delegate with one parameter :
#region Delegates
public delegate void TurnUnitEventHandler(TurnUnit pTurnUnit)
#endregion

Events declaration

I have implemented onUnitTurnStarted and onUnitTurnEnded. You can customize it with more events if you want.
#region Events declaration<br><br>        
    public TurnUnitEventHandler onTurnStarted, onTurnEnded;
    public TurnUnitEventHandler onActionPointAdded, onActionPointConsumed;        #endregion

Trigger events

I always create functions to trigger events. Here is the unity’s implementation :
#region Events

public void OnTurnStarted()
{
    if (onTurnStarted != null)
        onTurnStarted(this);
}

public void OnTurnEnded()
{
    if (onTurnEnded != null)
        onTurnEnded(this);
}
#endregion

Initialisation of the TurnUnit.cs component

As you can see, all my scripts have an Init() function. That’s the case for this script too :

/// 
/// Use this function to initialize the unit turn
/// 
public void Init(
    float pOriginalTurnTime,
    eTurnUnitState pState
    )
{
    ////////////////////////////////////
    // properties
    originalTurnTime = pOriginalTurnTime;
    currentTurnTime = pOriginalTurnTime;
    state = pState;
    turnNumber = 1;
}

Remove time from the unit timer

To reduce the wait time before the unit turn begin, we need a function for modifying the property. There is a little subtility. We only remove time if the unit is in the battle 
/// 
/// Remove time from the unit turn
/// 
public void RemoveTurnTime(float pTime)
{
    if (state == eTurnUnitState.IN_BATTLE)
        timeLeftUntilTurnBegin -= pTime;
}

Check if the unit can start its turn

The way to know if a unit can start a turn is very simple. If the property “timeLeftUntilTurnBegin” is lower than 0, it means that the unit can start.

Start and End turns

These functions are simple too but don’t need to forget to trigger events :
/// 
/// Use this method to start the turn
/// 
public void StartTurn()
{

    //Trigger event
    OnTurnStarted();

    //Increase turn number
    turnNumber++;
}

/// 
/// Use this method to end the unit turn
/// 
public void EndTurn()
{
    //Add time for next turn
    timeLeftUntilTurnBegin += currentTurnTime;

    //Trigger event
    OnTurnEnded();
}

And that’s all ! We finally created our unit turn based component. In the next article, i will add 1 extra feature : Action Points

These feature are used on tactic game. Our turn battle system can be used on this kind of game too. So it’s interesting to implement it.

Hope you’ve appreciate this article.
Let me know if you have some trouble or if you have some question.

See you soon,
D.

Create a RPG Battle system with Unity 3D – Part 2 – TurnManager.cs

TurnManager.cs : What should it do ?

This script is a component wich will handle all the turn batlle system mechanics. To resume it clearly, it will be in charge of :
  • Time Battle Management : run when no unit is acting, stop when a turn starts et resume when a turn ends.
  • Update elapsed time for all units
  • Start unit turn if is it’s turn
At the end of the tutorial, you will be able to handle battle like this kind of game (I hope you recognized it)
Final fantasy 9 – SquareSoft – 2000

Enums

We’ll use an enum for defining the turn manager state as following : 
#region Enums
public enum eTurnManagerState
{
    NOT_INITIALIZED,    //the turn manager has not been initialized
    INITIALIZED,        //Initialized !
    RUNNING,            //Currently running, no unit is acting
    PAUSED,             //The turn manager is paused, no time is elapsing right now...
} 
#endregion

Properties 

For handling all these features, we’ll need all these properties : 
#region Properties

/// 
/// List of all units in the battle
/// 
private List unitList;

/// 
/// State of the turn manager
/// 
private eTurnManagerState state;

/// 
/// Unit to have to begun its turn
/// 
private Queue unitTurnList;

/// 
/// Elapsed time since beggining of the battle
/// 
private float elapsedTime { get; set;  }

/// 
/// Current unit acting
/// 
public TurnUnit currentUnitTurn;

#endregion

I will not define all these properties because it’s cleary named and commented.

Functions

To sum up all the needed function for the turn battle manager system :
  • Init : Initialize the component 
  • GetAllUnitInBattle : Get all game objects with a TurnUnit.cs component (will be provided in the next article)
  • UpdateUnitTime : Update Unit elapsed time
  • CheckIfUnitCanStartItsTurn : Check if a unit can start it’s turn, if yes, start the turn !
  • Run : Run the timer
  • Pause : Pause the timer
Here is the Unity’s implementation :
#region Implementation

/// 
/// Use this function to initialize the component
/// 
public void Init()
{
    ////////////////////////////////////
    // properties
    GetAllUnitInBattle();
    unitTurnList = new Queue();
    currentUnitTurn = null;

    state = eTurnManagerState.INITIALIZED;
}

/// 
/// Get All the unit in battle
/// 
private void GetAllUnitInBattle()
{
    unitList = new List();

    foreach(TurnUnit turnUnit in FindObjectsOfType())
    {
        unitList.Add(turnUnit);
        //Suscribe unit events
        turnUnit.onTurnStarted += OnUnitTurnStarted;
        turnUnit.onTurnEnded += OnUnitTurnEnded;
    }
}

/// 
/// Update Unit elapsed time
/// 
private void UpdateUnitTime(float pTime)
{
    foreach(TurnUnit turnUnit in unitList.OrderBy(unit => unit.timeLeftUntilTurnBegin))
    {
        turnUnit.RemoveTurnTime(pTime);

        if (turnUnit.CanStartTurn())
            unitTurnList.Enqueue(turnUnit);
    }
}

/// 
/// Check if a unit can start its turn, if yes, start it
/// 
public void CheckIfUnitCanStartItsTurn()
{
    if(unitTurnList.Count > 0)
    {
        currentUnitTurn = unitTurnList.Dequeue();
        currentUnitTurn.StartTurn();
    }                
}

/// 
/// Use this function to start the timer
/// 
public void Run()
{
    state = eTurnManagerState.RUNNING;
}

/// 
/// Use this function to stop the timer
/// 
public void Pause()
{
    state = eTurnManagerState.PAUSED;
}

#endregion

Events subscription

As you can see, we’ve suscribded to unit’s events on the GetAllUnitInBattle() function. In fact these event are necessary to : 
  • Pause the timer when the unit begin it’s turn.
  • Resume the timer when the unit has ended its turn
Here is the code of these two function :
#region Events Suscribed

public void OnUnitTurnStarted(TurnUnit pTurnUnit)
{
    Pause();
}

public void OnUnitTurnEnded(TurnUnit pTurnUnit)
{
    currentUnitTurn = null;
    Run();
}

#endregion

Unity callbacks

Now we have all the logic implemented, we can just run the timer in the Unity Update() built-in function as below : 
void Awake()
{
    state = eTurnManagerState.NOT_INITIALIZED;
}

void Update()
{

    CheckIfUnitCanStartItsTurn();

    if (state == eTurnManagerState.RUNNING)
    {
        this.elapsedTime += Time.deltaTime;
        UpdateUnitTime(Time.deltaTime);
    }
}
At this point, we have a turn battle system totally functionnal but no unit… Of course, it will be provided to you the in the next article.
It will be a little more complicated, but not so much. Don’t give up !
If you have some review or questions, feel free to post it !
Thanks you for reading. All feedback is appreciated.

Create a RPG battle system with Unity 3D – Part 1 – Concept

Setting up an old school RPG battle system

Nowadays, old J-RPG battle system are not very used, letting the field to mixed action-RPG battle system (FFXV for exemple).

Mechanics used by J-RPG system may seems old, not fun or borring.. but in fact, we can build really great game with some clever ideas… making the game immersive and fun to play. One of the best J-RPG game was without any doubt Final Fantasy 7 developped by the talentuous Squaresoft studio in 1997

Final fantasy 7 – SquareSoft – 1997

Mechanism explanation

What is a J-RPG battle system ? That’s a battle system wich is :

  • Turn based : One unit can act at one time
  • Simple to implement
  • Pleasant to play

3 good reasons to base our new RPG game on this system. For this tutorial, we’ll use Unity 3D 2018. In fact, many of my articles are based on Unity 3D.

No worries, if you are using another game engine (Unreal Engine for exemple…), my articles will be really usefull too..

Next articles

I’ve splitted this course as following :

  1. TurnManager.cs : Implementing the core of the J-RPG battler 
  2. UnitTurn.cs : Implementing unit features as StartTurn(), EndTurn(), … 
  3. Usage example 
Of course, if i found ideas to improve this tutorial, i will implement them and share them with you