top of page

JRPG Combat System: Updated

Group Size: 1

Duration: 1 week, August 2022

Program: Unity 2021

A few months ago, I made a battle system inspired by classic JRPGs, like Final Fantasy and Dragon Quest. It was a fun project for college, if a bit simple. It was lacking in terms of mechanics and systems. As such, I decided to expand upon the already existing mechanics to make a more robust and interesting combat system.

For the player, there are a few new and interesting mechanics. The most noticeable of these is the magic system. The player and enemy both now have mana bars where they can use certain spells. This creates a certain level of risk and reward when it comes to magic. Although using magic is guaranteed to hit, it typically does less damage than physical attacks, and costs a small amount of mana. Speaking of magic attacks, the player now has access to four magic based attacks, each with their own properties and damage numbers. For example, the fire attack does a moderate amount of damage, and has a 30 percent chance to burn the enemy, causing damage every turn for a set number of turns; the ice attack does low damage, and has a 40 percent chance to freeze the enemy, preventing them from attacking; etc. The most interesting of these is the life steal spell, which takes a randomized number of health from the enemy, and adds it to the player's health bar. It costs double the amount of mana from a standard heal, but it's guaranteed to heal more than a regular heal.

Enum Statement for Different Magic Attacks

MagicEnum.PNG
MagicFunc1.PNG
MagicFunc2.PNG

Examples of different magic attacks being used.

Another new system for the player is the ability to escape battles. All the player has to do is press the escape button, and the battle will be over with no victors. This is something I've seen in many RPGs for when the player doesn't feel like using any resources. However, there are certain scenarios where escape isn't possible, or times where escape can fail. For my system, escape is guaranteed no matter what. That's something I will work to fix in a future update.

The results at the end of the battle. Either the player wins, the enemy wins, or the player escapes successfully.

EscapeButton.PNG

The battle state changes from the player's turn to the player escaping, and ends the battle.

EndBattle.PNG

The enemy unit also has its own updated mechanics. For starters, there are now multiple enemy types. The main change between each enemy type is in health, mana, and damage output. This change is also applied to the player character, for the purpose of scaling. However, there's another change created specifically for the final boss, which is the addition of a second phase, and a unique attack. All of this is done through setting an enumerator to which enemy type you'd like to try out. From there, the program scales enemy and player variables properly, and the battle begins.

BattleTypeStart.PNG

Enemy Type Switch Statement

Updated Battle Set-Up Function

NewBattleStart.PNG

Speaking of enemies, and as mentioned prior, the final boss has a dedicated second phase. When its health is reduced to half, it will use a special attack that is unique to this battle. The attack does more damage than any other standard attack, but the boss will have to recharge for a few turns before taking action again. Once phase two has been activated, the boss has a low chance to use that special attack at any point during the battle. This creates a battle that is more layered, as well as potentially more challenging than other battles.

Function that triggers the start of the second phase of a boss fight.

Phase2Begin.PNG
FinalBossAttack.PNG

Condition that activates an attack specific to the second phase of a boss fight.

Updating the combat system presented a few challenges. Since it's a turn based system with a lot of lingering dialogue, many coroutines had to be used to get everything functioning. However, this sometimes lead to functions ending early if not managed properly. The solution to this was to re-think the structure of coroutines, and adjust accordingly. For example, when the enemy's turn started, there's a function that checks if they have any status effects, and apply those effects accordingly. However, since I placed the coroutine at the end of the enemy's turn, it would fall out as soon as "yield return" was hit. My solution to this was surprisingly simple: call the status function at the end of the player turn function, rather than the beginning of the enemy turn function. Then, call the enemy turn function at the end of the status coroutine. The results work beautifully.

PathToStatus.PNG

Coroutine from Player Turn function to Status function.

Coroutine from Status function to Enemy Turn function.

PathToEnemyPhase.PNG

In the end, this was a fun update to a previously established system. It allowed me to think beyond the current scope, and experiment with mechanics I hadn't yet tried out. It had its own challenges, but I managed to figure out those solutions with relative ease.

The combat system can be played here

bottom of page