From Test-Scratch-Wiki
This article or section may not have content matching Scratch Wiki editing standards. Please improve it according to Scratch Wiki:Guidelines. Reason: informal language |
A Turn-based RPG is a type of role playing game. In turn-based RPGs, battles consist of turns where a player can command their characters to perform various actions to defeat opponents. Turn-based RPGs are one of the most popular types of RPGs on gaming consoles, but are not very popular as Scratch projects.
This article contains a guide on how to create a turn-based system for an RPG.
When finished, the project should look something like this.
Game Statistics
Turn based RPG battles focus mainly on statistics and formulas. In this tutorial the player has the following statistics:
Atk: Physical attack power
Def: Physical defense
MaxHP: Most HP (Health Points) the character can have
HP: Health points, the player is dead when this is at 0
MaxMP: Most MP (Magic Points) a character can have
MP: Magic points, used for magic attacks
MGAtk: Magic attack power
MGDef: Defense from magic attacks
Additionally, the player character has statistics for their weapons:
Atk: A set increase in attack power P: A random increase in attack power
An enemy has the same statistics as the player character except without the extra statistics for weapons and Magic Points.
The first thing you should do is create the statistic variables. Variables belonging to the player character should start with "C_" those belonging to the player character's weapon should start with "C_Wep" and those belonging to the enemy should start with "E_".
We are also going to gives the variables some test values when the green flag is clicked so that we may properly play the game during testing. When finished, your set of variables should look something like this:
When flag clicked set [C_Atk v] to [5] set [C_Def v] to [5] set [C_MGAtk v] to [15] set [C_MGDef v] to [5] set [C_MaxMP v] to [100] set [C_MP v] to (C_MaxMP) set [C_MaxHP v] to [100] set [C_HP v] to (C_MaxHP) When flag clicked set [C_Wep_Atk v] to [5] set [C_Wep_P v] to [5] When flag clicked set [E_Atk v] to [5] set [E_Def v] to [10] set [E_MaxHP v] to [120] set [E_HP v] to (E_MaxHP) set [E_MGAtk v] to [0] set [E_MGDef v] to [0]
Battle Formulas
Next up is adding the formulas for the different attacks. The variables you have just created fit snugly into those formulas. The formulas we will use are based on a classic RPG called Super Mario RPG.
Player Melee Attack Damage Formula:
C_Atk(C_Wep_Atk+(pick random (0-C_Wep_P) to (C_Wep_P))-E_Def)
(((C_Atk) + ((C_Wep_Atk) + (pick random ((0) - (C_Wep_P)) to (C_Wep_P)))) - (E_Def))
Player Magic Attack Damage Formula:
C_MGAtk+"spellrating"-E_MGDef
(((C_Atk) + (22)) - (E_MGDef))
- Each spell has a strength rating which must be set.
Enemy Melee Attack Damage Formula:
E_Atk-C_Def
((E_Atk) - (C_Def))
Enemy Magic Attack Damage Formula:
E_MGAtk+"spellrating"-C_MGDef
(((E_MGAtk) + (0)) - (C_MGDEF))
- Each enemy spell has a strength rating which must be set.
You need to build these scripts and leave them on the stage. They will be used as parts of the scripts for the battle actions.
Programming Actions
Now that we know how the game will handle formulas and stats, it is time to allow the user to play a simple RPG game.
To control the game, we need a few variables that serve to make the game run as opposed to building the battle formulas.
You will now need to create the following variables:
dam: Stores the results of the damage calculations
gamestate: Tells the game what is currently supposed to be doing e.g. letting the player pick attacks, or letting the enemy character attack
- The number of the gamestate variable tells the program different things. This is the list of values for the variable:
1. Wait for player to enter a command
2. Wait for player character animation to finish
3. Allow the enemy to pick an action and carry it out
0. The RPG battle is over
C_Stance: Tells the character sprite which animation to play e.g. standing, attacking, cast spell.
E_Stance: Tells the enemy sprite which animation to play e.g. standing, attacking, cast spell.
- The stance variables tell the which animations to play, for this game we will make the following animations:
- Idle animation
- Attack animation 1 (melee)
- Attack animation 2 (spell)
- Hurt animation
- Death animation
You will also need the following Broadcasts:
melee: Makes the player character use a melee attack
spell: Makes the player character do a magic attack
emelee: Makes the player character use a melee attack
espell: Makes the player character do a magic attack
stance: Tells the player sprite to do an animation
enemy_stance: Tells the enemy sprite to do an animation
Now, create the following scripts on the stage
when I receive [melee v] set [C_Stance v] to [2] set [gamestate v] to [2] broadcast [stance v] and wait set [dam v] to (((C_Atk) + ((C_Wep_Atk) + (pick random ((0) - (C_Wep_P)) to (C_Wep_P)))) - (E_Def)) if <(dam) < (0)> then set [dam v] to (0) end change [E_HP v] by ((-1) * (dam)) set [E_Stance v] to [4] broadcast [E_stance v] and wait set [gamestate v] to [3] set [C_Stance v] to [1] broadcast [stance v] when I receive [spell v] set [C_Stance v] to [3] set [gamestate v] to [2] broadcast [stance v] and wait set [dam v] to (((C_Atk) + (22)) - (E_MGDef)) if <(dam) < (0)> then set [dam v] to [0] end change [E_HP v] by ((-1) * (dam)) set [E_Stance v] to [4] broadcast [E_stance v] and wait set [gamestate v] to [3] set [C_Stance v] to [1] broadcast [stance v] when I receive [emelee v] set [E_Stance v] to [2] broadcast [E_stance v] and wait set [dam v] to ((E_Atk) - (C_Def)) if <(dam) < (0)> then set [dam v] to [0] end change [C_HP v] by ((-1) * (dam)) set [C_Stance v] to [4] broadcast [stance v] and wait set [E_Stance v] to [1] broadcast [E_stance v] and wait set [gamestate v] to [1] when I receive [espell v] set [E_Stance v] to [3] broadcast [E_stance v] and wait set [dam v] to (((E_MGAtk) + (0)) - (C_MGDef)) if <(dam) < (0)> then set [dam v] to [0] end change [C_HP v] by ((-1) * (dam)) set [C_Stance v] to [4] broadcast [stance v] and wait set [E_Stance v] to [1] broadcast [E_stance v] and wait set [gamestate v] to [1]
You will also need a way to allow the player to broadcast these actions so make 2 buttons with the following scripts:
Melee Button
when I am clicked if <(gamestate) = (1)> then broadcast [melee v] end when flag clicked forever if <(gamestate) = (1)> then show else hide end
Spell Button
when I am clicked if <<(gamestate) = (1)> and <<(C_MP) > (15)> or <(C_MP) = (15)>>> then broadcast [spell v] and wait change [mp v] by (-15) end when flag clicked forever if <(gamestate) = (1)> then show else hide end
The player should only be able to press these buttons when the gamestate variable is at 1 so we hide them if the variable is not at one. The buttons work in similar ways but the spell button check to see if the player has enough MP and only make the broadcast if there is enough MP.
As a finishing touch we are going to set the variables that are not involved in the battle formulas to a default value.
when flag clicked switch to background [background1 v] set [gamestate v] to [1] set [C_Stance v] to [1] set [E_Stance v] to [1] broadcast [stance v] broadcast [E_stance v]
Character Animation
You will need an animation for each stance, you can either draw them yourself, download a premade sprite sheet, or use a sprite generator such as the Charas-Project Generator
For this project, I will personally use the Charas generator for quick and easy sprites but those who are more artistically inclined can draw them. If you are not drawing sprite then you must import the sprite sheets and cut the sprite out. For a quick guide on how to do this go to this forum topic.
The animations that we need are the following:
- Idle animation
- Attack animation 1 (melee)
- Attack animation 2 (spell)
- Hurt animation
- Death animation
We want the character sprites to play a little animation every time the stance broadcasts are called so we need a script like this one. The blocks inside the if blocks are for the animations are can be customized in any way you like.
when I receive [stance v] if <(C_HP) < [1]> then switch to costume [dead_1 v] else if <(C_Stance) = [1]> then switch to costume [idle v] end if <(C_Stance) = [2]> then switch to costume [idle v] move (100) steps switch to costume [melee_1 v] wait (0.1) secs switch to costume [melee_2 v] wait (0.1) secs switch to costume [melee_3 v] wait (0.1) secs go to x: (-90) y: (-89) switch to costume [idle v] end if <(C_Stance) = [3]> then switch to costume [idle v] move (100) steps switch to costume [spell_1 v] wait (1) secs go to x: (-90) y: (-89) switch to costume [idle v] end if <(C_Stance) = [4]> then say (dam) switch to costume [hurt_1 v] repeat (3) move (-10) steps end repeat (3) move (10) steps end wait (0.5) secs switch to costume [idle v] say [] end end
The script for the enemy sprite will look the same except that the broadcast will be the enemy's broadcast (E_stance) and the stance variable will belong to the enemy (E_stance).
A picture of the enemy script can be seen below.
when I receive [E_stance v] if <(E_HP) < [1]> then switch to costume [dead_1 v] else if <(E_Stance) = [1]> then switch to costume [idle v] end if <(E_Stance) = [2]> then switch to costume [idle v] move (100) steps switch to costume [melee_1 v] wait (0.1) secs switch to costume [melee_2 v] wait (0.1) secs switch to costume [melee_3 v] wait (0.1) secs go to x: (90) y: (-89) switch to costume [idle v] end if <(E_Stance) = [3]> then switch to costume [idle v] move (100) steps switch to costume [spell_1 v] wait (1) secs go to x: (90) y: (-89) switch to costume [idle v] end if <(E_Stance) = [4]> then say (dam) switch to costume [hurt_1 v] repeat (3) move (-10) steps end repeat (3) move (10) steps end wait (0.5) secs switch to costume [idle v] say [] end end
Automating the Enemy
Since the enemy does not have a player to control its actions, it will do so on its own.
Build this script on the enemy sprite and it should attack the player by itself when gamestate is equal to 3.
when flag clicked forever if <(gamestate) = [3]> then if <(E_HP) < [1]> then broadcast [win_battle v] and wait end if <(gamestate) = [3]> then set [randAtk v] to (pick random (1) to (2)) if <(randAtk) = [1]> then broadcast [emelee v] and wait end if <(randAtk) = [2]> then broadcast [espell v] and wait end if <(C_HP) < [1]> then broadcast [lose_battle v] and wait end end end
This script as you can see also is able to call the broadcasts that end the game, the win_battle and lose_battle broadcasts.
Ending the Game
There are two conditions in which the game ends:
- The player loses all HP and loses the game
- The enemy character loses all HP and the player wins
As you can see from the above script that automates the enemy, the enemy checks to see if these conditions have been fulfilled and calls the appropriate broadcast.
In the demo project, a different background plays and the gamestate is set to 0, which means that the battle sequence is done.
when I receive [lose_battle v] set [gamestate v] to [0] switch to background [background3 v] when I receive [win_battle v] set [gamestate v] to [0] switch to background [background2 v]
Finishing Remarks
Test your project out, if you followed this tutorial correctly, then you should have a working RPG project. If it is not working then it is likely you did not correctly copy the scripts in this article. The best way to troubleshoot is to compare it with the example one given at the start of this article.