- Home /
Need help making a pokemon turn based system !
I've been trying to make a turn based game for about 2 weeks now and i decided to make the Battle System first and then do the overworld scene (think pokemon). Unfortunately, it's been a week and I still didn't find how to implement a turn based system based on speed (like pokemon). Since i can't do that I cannot implement a health bar and a damage value(I don't know how to do that but I'll find after the Battle System works). I watched a lot of tutorials on the subject, but the thing is that tutorial aren't always made for what you want to do and in my case, they weren't. However i learned a lot from them and was able to do a lot of stuff (make my battle canvas and ui button) but I still don't know how to make a turn based combat system ! All I want to do for now is make enum states where the player moves and then the enemy or the enemy and then the player (based on speed) I don't know how to make them do damage yet but I don't need it right now. My BattleFlow script (which take care of the different states in a battle) doesn't seem to work well and when im trying to make my system work either a) Both the player and the enemy moves at the same time or b) only the player moves and the enemy don't (since my player as a bigger speed value than my enemy). Sometimes it even loops and my player (sometimes my enemy) just keep moving and then going back to his original position.
Here's my code for the battleflow : using System.Collections; using System.Collections.Generic; using UnityEngine;
public class BattleFlow : MonoBehaviour {
private BattleStart battleStartScript = new BattleStart();
public GameObject BattleMenu;
public GameObject InfoPanel;
public GameObject MovesInfo;
public GameObject MessagePanel;
public enum BattleStates
{
Start,
ChoicePhase,
PlayerPhase,
EnemyPhase,
UpdatePhase,
Lose,
Win
}
private void Awake()
{
//currentState = BattleStates.Start;
currentState = BattleStates.Start;
}
public static BattleStates currentState;
void Start () {
}
// Update is called once per frame
void Update () {
Debug.Log(currentState);
switch(currentState)
{
case (BattleStates.Start):
battleStartScript.PrepareBattle();
break;
case (BattleStates.ChoicePhase):
battleStartScript.NextTurn();
break;
case (BattleStates.PlayerPhase):
break;
case (BattleStates.EnemyPhase):
break;
case (BattleStates.UpdatePhase):
break;
case (BattleStates.Win):
break;
case (BattleStates.Lose):
break;
}
if (currentState == BattleStates.Start)
{
currentState = BattleStates.ChoicePhase;
}
if (currentState == BattleStates.ChoicePhase)
{
BattleMenu.SetActive(true);
InfoPanel.SetActive(false);
MessagePanel.SetActive(false);
if (GameObject.Find("BattleMainMenu").GetComponent<BattleMenuScript>().playeraction1)
{
currentState = BattleStates.PlayerPhase;
}
if (GameObject.Find("BattleMainMenu").GetComponent<BattleMenuScript>().playeraction2)
{
currentState = BattleStates.PlayerPhase;
}
if (GameObject.Find("BattleMainMenu").GetComponent<BattleMenuScript>().playeraction3)
{
currentState = BattleStates.PlayerPhase;
}
if (GameObject.Find("BattleMainMenu").GetComponent<BattleMenuScript>().playeraction4)
{
currentState = BattleStates.PlayerPhase;
}
}
if ((currentState == BattleStates.PlayerPhase) && (GameObject.Find("Jibakurei").GetComponent<JibakureiCon>().AllyIsDone))
{
currentState = BattleStates.EnemyPhase;
}
if (currentState == BattleStates.EnemyPhase)
{
}
if (currentState == BattleStates.UpdatePhase)
{
BattleMenu.SetActive(false);
InfoPanel.SetActive(false);
MovesInfo.SetActive(false);
MessagePanel.SetActive(true);
//CalculateDamage
if (Input.GetKeyDown(KeyCode.Z))
{
currentState = BattleStates.ChoicePhase;
}
}
}
}
The player :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class JibakureiCon : MonoBehaviour
{
public static int Speed = 10;
public static int Atk = 8;
public static int maxHP = 20;
public static int HP = 20;
public static int Def = 6;
public BattleFlow.BattleStates battleStates;
public bool SlashUsed;
public bool AllyIsDone;
private void Start()
{
battleStates = BattleFlow.BattleStates.ChoicePhase;
}
private void Update()
{
if (GameObject.Find("BattleMainMenu").GetComponent<BattleMenuScript>().playeraction1)
{
battleStates = BattleFlow.BattleStates.PlayerPhase;
}
if ((battleStates == BattleFlow.BattleStates.ChoicePhase) && (GameObject.Find("BattleMainMenu").GetComponent<BattleMenuScript>().playeraction1))
{
SlashUsed = true;
print("UsedSlash!");
battleStates = BattleFlow.BattleStates.PlayerPhase;
}
if (battleStates == BattleFlow.BattleStates.PlayerPhase)
{
SlashUsed = true;
}
if ((SlashUsed == true) && (battleStates == BattleFlow.BattleStates.PlayerPhase))
{
GetComponent<Transform>().position = new Vector2(-11.80f, -0.50f);
StartCoroutine (JibakureiReturn());
AllyIsDone = true;
battleStates = BattleFlow.BattleStates.EnemyPhase;
}
if (AllyIsDone == true)
{
battleStates = BattleFlow.BattleStates.EnemyPhase;
}
}
IEnumerator JibakureiReturn()
{
yield return new WaitForSeconds(1.2f);
GetComponent<Transform>().position = new Vector2(-15.31f, -3.62f);
print("AllyTurn");
battleStates = BattleFlow.BattleStates.EnemyPhase;
}
}
and the enemy :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnkuzenCon : MonoBehaviour
{
public static float enemyHP = 25;
public static int speed = 8;
public BattleFlow.BattleStates battleStates;
// Use this for initialization
void Start()
{
}
void Update()
{
if ((battleStates == BattleFlow.BattleStates.EnemyPhase))
{
print("EnemyTurn");
GetComponent<Transform>().position = new Vector2(-13.16f, -0.53f);
StartCoroutine(enemyReturn());
battleStates = BattleFlow.BattleStates.UpdatePhase;
}
else if ((battleStates == BattleFlow.BattleStates.EnemyPhase))
{
print("EnemyTurn");
GetComponent<Transform>().position = new Vector2(-13.16f, -0.53f);
StartCoroutine(enemyReturn());
battleStates = BattleFlow.BattleStates.UpdatePhase;
}
}
IEnumerator enemyReturn()
{
yield return new WaitForSeconds(1.2f);
GetComponent<Transform>().position = new Vector2(-9.5f, 2f);
print("AllyTurn");
battleStates = BattleFlow.BattleStates.UpdatePhase;
}
}
If anything isn't clear I'm sorry, just ask and i'll respond. English isn't my first language so sorry if I made any mistakes in my writing. Thanks for reading.
Answer by KvaljeanB · Oct 08, 2017 at 07:50 PM
First thing I'd say is you need a function to handle starting battle. I see you're doing it in awake but that only works once so if you ever want more than one battle you'll need a function. Second you are using Get component way to much you your update function, this will cause major lag later on, just drop them in the Start Function or Awake and you'll be fine. as for the system it's self I have .o clue how it works, never played pokemone before but, this is how i'd do it.
pseudo-code
// You Might want an array of enemy's or an array of players idk. void Start Battle(Gameobject player, Gameobject enemy) { // Opens the battle screen OpenBattlescreen(); // Enemy chooses an attack. enemy.ChoseAttack(); // Gets input from player player.ChoseAttack } // Decides who go's first, how much damage is done etc. void Battle(Gameobject player, Gameobject enemy)
{ if(player.Attack.attackSpeed > enemy.Attack.attackspeed) { player.Attack();
if(enemy.health > 0) { enemy.Attack(); } else if(player.Attack.attackSpeed < enemy.Attack.attackspeed) { enemy.Attack(); if(player.health > 0) { player.Attack(); } else { pickRandomPlayerToAttackFirst(); } } That's the basic Idea. If you need actual syntax, I'll help out, I've been thinking of make a system like this.
Happy coding.
—K.Valjean.B
Thanks a bunch ! Yeah, I would like to see how you do it to help me making my own. Also, from what i know an array is a list of variables how does that help me ? Is there something more to arrays ? Thanks for the advice about GetComponent, if i drop them in the start function is it going to be run every turns (how do i even make turns ? (Something like that right ? : Start Turn, ChoicePhase, PlayerPhase, EnemyPhase, UpdatePhase (calculating damage and all that) and then StartTurn again ?)) or only once ? These may be beginners questions but i'm fairly new in coding so sorry. Thanks for your help !
Here's the basic Idea uing System.Collections; using System.Collections.Generic; using UnityEngine; public class Battle$$anonymous$$anager : $$anonymous$$onoBehaviour { // Enum to keep track of where we are in a battle. enum BattlePhase { Start, Players, Ememys, Choice } // You'd need a play script to hold an array of the players $$anonymous$$m and the enemy would have to pass this an array of enemys but I'll hard code them in for now :) public GameObject[] Enemies= new GameObject[3]; public GameObject[] Allies = new GameObject[3]; public GameObject BattleScene; public GameObject Enemy; // Current Phase in battle. BattlePhase currentBattlePhase; // Use this for initialization void Start () { InitiateBattle(); } // Update is called once per frame void Update () { } //Initilize Battle, variables public void InitiateBattle() { currentBattlePhase = BattlePhase.Start; BattleScene = GameObject.Find("Battle Screen"); startBattle(Enemies, Allies); } // Play Battle start animation animations public void startBattle(GameObject[] Enemies, GameObject[] Allies) { // Playanimation(); // Enemies[0].SelectAttack(); // GetPlayersAttack(); } // This will decide how many times the player or enemy will attack per-round based on the attack speed. // I.E if players attack speed = 1 and the Enemys attack = 1 (1 / 1) = 1 therfore both partys with attack one time this round. // how ever if the players attack is = 2 and the enemys attack is = 1 (2 / 1) = 2 the player will attack twice and the enemy (1 / 2) = 0.5 rounded = 1 the enemy attacks 1 time. public void SetAttackOrder(int enemyAttackSpeed, int playerAttackSpeed) { int enemiesNumberOfAttacksThisRound = $$anonymous$$athf.RoundToInt((enemyAttackSpeed / playerAttackSpeed)); int playerNumberOfAttacksThisRound = $$anonymous$$athf.RoundToInt((enemyAttackSpeed / playerAttackSpeed)); GameObject FirstAttacker; if(enemyAttackSpeed > playerAttackSpeed) { // whichever enemy is currenlty on screen i'll just put the first one in FirstAttacker = Enemies[0]; } else { FirstAttacker = Allies[0]; } startRound(enemiesNumberOfAttacksThisRound, playerNumberOfAttacksThisRound, FirstAttacker ); } public void startRound(int numberOfEnemyAttacks, int numberOfPlayerAttacks, GameObject FirstAttacker) { // set who go's first based on attack speed, } }
Don't really have time to work on this but it should help.
—$$anonymous$$.Valjean.B
Thanks ! I'll try seeing what i can do with this. I'll keep you updated !