I decided to start doing an RPG, so I learned to use state machines. The problem is that by testing them, the enemy constantly debugs their damage, so I decided to add calls to the state WAITING
, both in the hero and in the enemy. Now the enemy never attacks, is there any way to solve this?
Here is my battle state machine :
using UnityEngine; using System.Collections; using System.Collections.Generic; using UnityEngine.UI;
public class BattleState : MonoBehaviour {
public enum performAction
{
WAIT,
TAKEACTION,
PERFORMACTION
}
public performAction battleStates;
public List<HandleTurn> PerformList = new List<HandleTurn>();//lista de actores
public List<GameObject> HeroInGame = new List<GameObject>();//heroes en la escena
public List<GameObject> EnemiesInBattle = new List<GameObject>();//enemigos en la escena
public enum HeroGUi//acciones posibles del heroe
{
ACTIVATE,
WAITING,
INPUT1,
INPUT2,
DONE
}
public HeroGUi HeroInput;
public List<GameObject> HeroesToManage = new List<GameObject>();
private HandleTurn HeroChoice;
public GameObject enemyButton;
public Transform Spacer;
public GameObject AttackPanel;
public GameObject EnemySelectPanel;
public GameObject StatusPanel;
// Use this for initialization
void Start ()
{
battleStates = performAction.WAIT;
EnemiesInBattle.AddRange(GameObject.FindGa
meObjectsWithTag("Enemy"));
HeroInGame.AddRange(GameObject.FindGameObjectsWithTag("Hero"));
HeroInput = HeroGUi.ACTIVATE;
AttackPanel.SetActive(false);
EnemySelectPanel.SetActive(false);
StatusPanel.SetActive(false);
CreateEnemyButtons();
}
// Update is called once per frame
void Update ()
{
if (HeroSM.inBattle == true)
{
StatusPanel.SetActive(true);
switch (battleStates)
{
case (performAction.WAIT):
if (PerformList.Count > 0)//revisa la lista
{
battleStates = performAction.TAKEACTION;
}
break;
case (performAction.TAKEACTION):
GameObject performer = GameObject.Find(PerformList[0].Attacker);
if (PerformList[0].Side == "Enemy")
{
EnemySM ESM = performer.GetComponent<EnemySM>();
ESM.HeroToAttack = PerformList[0].TargetGO;
EnemySM.currentEnemyTurn = EnemySM.enemyTurn.ACTION;
HeroSM.currentHeroTurn = HeroSM.heroTurn.WAITING;
}
if (PerformList[0].Side == "Hero")
{
HeroSM HSM = performer.GetComponent<HeroSM>();
HSM.EnemyToAttack = PerformList[0].TargetGO;
HeroSM.currentHeroTurn = HeroSM.heroTurn.ACTION;
EnemySM.currentEnemyTurn = EnemySM.enemyTurn.WAITING;
}
battleStates = performAction.PERFORMACTION;
break;
case (performAction.PERFORMACTION):
//iddle
break;
}
//switch para el estado del heroe
switch (HeroInput)
{
case (HeroGUi.ACTIVATE):
if (HeroesToManage.Count > 0)
{
print("im active yo!");
HeroesToManage[0].transform.FindChild("Selector").gameObject.SetActive(true);//tomamos al primer heroe de la lista, hallamos el padre, pasamos al hijo llamado selector y seteamos el booleano
HeroChoice = new HandleTurn();
AttackPanel.SetActive(true);
HeroInput = HeroGUi.WAITING;
}
break;
case (HeroGUi.WAITING):
//iddle
break;
case (HeroGUi.DONE):
HeroInputDone();
break;
}
}
}
public void CollectActions(HandleTurn handleInput)
{
PerformList.Add(handleInput);
}
void CreateEnemyButtons ()
{
foreach(GameObject Enemy in EnemiesInBattle)
{
GameObject newButton = Instantiate(enemyButton) as GameObject;
EnemySelectButton button = newButton.GetComponent<EnemySelectButton>();
EnemySM curEnemy = Enemy.GetComponent<EnemySM>();
Text buttonText = newButton.transform.FindChild("Text").gameObject.GetComponent<Text>();
buttonText.text = curEnemy.Enemy.baseName;
button.EnemyPrefab = Enemy;
newButton.transform.SetParent(Spacer, false);
}
}
public void Input1()//attack button
{
HeroChoice.Attacker = HeroesToManage[0].name;
HeroChoice.AttackerGO = HeroesToManage[0]; // ya es un gameobject asi que no lo especificamos
HeroChoice.Side = "Hero";
AttackPanel.SetActive(false);
EnemySelectPanel.SetActive(true);
}
public void InputEnemySelection(GameObject choosenEnemy)//enemy selection
{
HeroChoice.TargetGO = choosenEnemy;
HeroInput = HeroGUi.DONE;
}
void HeroInputDone()
{
PerformList.Add(HeroChoice);
EnemySelectPanel.SetActive(false);
AttackPanel.SetActive(true);
HeroesToManage[0].transform.FindChild("Selector").gameObject.SetActive(false);
HeroesToManage.RemoveAt(0);
HeroInput = HeroGUi.ACTIVATE;
}
}
This is the enemy state machine :
using UnityEngine; using System.Collections; using UnityEngine.UI;
public class EnemySM : MonoBehaviour {
public EnemyStats Enemy;//creamos a enemigo desde la plantilla
private BattleState BS;
public bool actionStarted = false;
public GameObject Description;
public enum enemyTurn
{
PROCESSING,
CHOOSEACTION,
WAITING,
ACTION,
DEAD
}
public static enemyTurn currentEnemyTurn;
//para cambiar las barras
private float curHealth;
public GameObject HeroToAttack;
// Use this for initialization
void Start()
{
currentEnemyTurn = enemyTurn.WAITING;
BS = GameObject.Find("BM").GetComponent<BattleState>();
}
// Update is called once per frame
void Update()
{
/* if (HeroSM.currentHeroTurn != HeroSM.heroTurn.WAITING)
{
currentEnemyTurn = enemyTurn.WAITING;
}*/
if (GMScript.InBattle == true)
{
curHealth = Enemy.CurrentHp;
switch (currentEnemyTurn)
{
case (enemyTurn.PROCESSING):
print("enemy processing");
currentEnemyTurn = enemyTurn.CHOOSEACTION;
break;
case (enemyTurn.CHOOSEACTION):
print("enemy chooseaction");
ChooseAction();
currentEnemyTurn = enemyTurn.WAITING;
break;
case (enemyTurn.WAITING):
//idle state
/*if (HeroSM.currentHeroTurn == HeroSM.heroTurn.WAITING)
{
currentEnemyTurn = enemyTurn.PROCESSING;
}*/
break;
case (enemyTurn.ACTION):
print("enemy action");
StartCoroutine(TimeForAction());
break;
case (enemyTurn.DEAD):
break;
}
}
}
void ChooseAction()
{
HandleTurn myAttack = new HandleTurn();
myAttack.Attacker = Enemy.baseName;
myAttack.Side = "Enemy";
myAttack.AttackerGO = this.gameObject;
myAttack.TargetGO = BS.HeroInGame[Random.Range(0, BS.HeroInGame.Count)];
int num = Random.Range(0,Enemy.Attacks.Count);//se genra un numero aleatorio entre 0 y la cantidad de ataques
myAttack.chooseAttack = Enemy.Attacks[num];//usamos el numero para escoger el ataque
Debug.Log(this.gameObject.name + " has choosen " + myAttack.chooseAttack.attackName + " and did " +myAttack.chooseAttack.attackDamage + " damage!!!");
BS.CollectActions(myAttack);
}
private IEnumerator TimeForAction ()//controla variables atraves del tiempo
{
if(actionStarted == true)
{
yield break;
}
actionStarted = true;
//wait
//do damage
DoDamage();
//remove from bs list
BS.PerformList.RemoveAt(0);//remueve al objeto en 0, el siguiente sube transformando el 1 en 0
//continua removiendo hasta desaparecer todo
//reset bs to wait
BS.battleStates = BattleState.performAction.WAIT;
//al pasar a wait y saltar a takeaction los objetos vuelven a crearse repitiendo el ciclo
//end coroutine
actionStarted = false;
currentEnemyTurn = enemyTurn.PROCESSING;
}
void DoDamage()
{
float calcDamage = Enemy.Fue * BS.PerformList[0].chooseAttack.attackDamage;
HeroToAttack.GetComponent<HeroSM>().TakeDamage(calcDamage);
}
}
This is the hero status machine :
using UnityEngine; using System.Collections; using UnityEngine.UI;
public class HeroSM : MonoBehaviour {
private BattleState BS;
public static bool inBattle;
public partyStat hero;//creamos a hero desde la plantilla
public enum heroTurn
{
START,
PROCESSING,
ADDTOLIST,
WAITING,
SELECTING,
ACTION,
DEAD
}
public static heroTurn currentHeroTurn;
//para cambiar las barras
private float curHealth;
public Image healthB;
public Image chamaB;
public GameObject selector;
public GameObject EnemyToAttack;
//ienumerator
private bool actionStarted;
// Use this for initialization
void Start ()
{
selector.SetActive(false);
BS = GameObject.Find("BM").GetComponent<BattleState>();
currentHeroTurn = heroTurn.START;
}
// Update is called once per frame
void Update ()
{
/*if (EnemySM.currentEnemyTurn != EnemySM.enemyTurn.WAITING)
{
currentHeroTurn = heroTurn.WAITING;
}*/
//creamos el movimiento de las barras de hp y chama
chamaB.transform.localScale = new Vector3(hero.CurrentChama / 100, this.transform.localScale.y, this.transform.localScale.z);
healthB.transform.localScale = new Vector3(hero.CurrentHp / 100, this.transform.localScale.y, this.transform.localScale.z);
curHealth = hero.CurrentHp;
if (GMScript.InBattle == true)
{
switch (currentHeroTurn)
{
case (heroTurn.START):
currentHeroTurn = heroTurn.PROCESSING;
break;
case (heroTurn.PROCESSING):
//inBattle = true;
//print("hero processing");
UpgradeBar();
break;
case (heroTurn.ADDTOLIST):
//print("hero addtolist");
BS.HeroesToManage.Add(this.gameObject);
currentHeroTurn = heroTurn.WAITING;
break;
case (heroTurn.WAITING):
//print("hero waiting");
/* if (EnemySM.currentEnemyTurn == EnemySM.enemyTurn.WAITING)
{
currentHeroTurn = heroTurn.START;
}*/
//idle
break;
case (heroTurn.ACTION):
//print("hero action");
StartCoroutine(TimeForAction());
break;
case (heroTurn.DEAD):
break;
}
}
}
void UpgradeBar()
{
currentHeroTurn = heroTurn.ADDTOLIST;
}
private IEnumerator TimeForAction()//controla variables atraves del tiempo
{
if (actionStarted == true)
{
yield break;
}
actionStarted = true;
//wait
//do damage
//remove from bs list
BS.PerformList.RemoveAt(0);//remueve al objeto en 0, el siguiente sube transformando el 1 en 0
//continua removiendo hasta desaparecer todo
//reset bs to wait
BS.battleStates = BattleState.performAction.WAIT;
//al pasar a wait y saltar a takeaction los objetos vuelven a crearse repitiendo el ciclo
//end coroutine
actionStarted = false;
currentHeroTurn = heroTurn.PROCESSING;
}
public void TakeDamage(float getDamageAmount)
{
hero.CurrentHp -= getDamageAmount;
if (hero.CurrentHp <= 0)
{
currentHeroTurn = heroTurn.DEAD;
}
}
}
Any data will be helpful.