前回は戦闘中に回復アイテムを使用する処理を実装しようとして、アイテムを使っている途中で動かなくなったところで終わりました。
バグの原因が不明なので、アイテムの使用処理の実装を置いておいて先に戦闘時の行動タイプによる処理分けを実装していきたいと思います。
実際の戦闘中の処理はBattleManagerが行っているのでBattleManagerに処理を追加していきます。
はじめに、戦闘中の行動の処理分けをするための列挙定数を宣言します。
public enum BATTLEACTIONTYPE
{
NORMALATTACK,
GUARD,
ITEM,
MAGIC,
MOVE,
};
それから、プレイヤーと敵のBATTLEACTIONTYPEを保持するためのDictionrayも宣言します。
private Dictionary<int, BATTLEACTIONTYPE> battleActionDic = new Dictionary<int, BATTLEACTIONTYPE>();
battleActionDicを初期化する関数を定義します。
public void InitBattleActionDic()
{
battleActionDic[0] = BATTLEACTIONTYPE.NORMALATTACK;
battleActionDic[1] = BATTLEACTIONTYPE.NORMALATTACK;
battleActionDic[2] = BATTLEACTIONTYPE.NORMALATTACK;
battleActionDic[3] = BATTLEACTIONTYPE.NORMALATTACK;
}
InitBattleActionDic関数をバトルのはじめに呼び出されるSetUpBattle関数で呼び出します。
public void SetUpBattle()
{
SoundManager.instance.PlayBGM("Battle");
player = PlayerManager.instance;
playerUI.SetupUI(player);
commandUI.gameObject.SetActive(true);
commandUI.SetBattleCommand();
battleResult = new BattleResult();
isBattleEnd = false;
InitBattleActionDic();
}
準最初の備ができたので、まずはプレイヤーの行動を処理分けできるようにしていきます。
BattleManager.csのTurnProcessの中で、行動順がプレイヤーの場合、StartPlayerTurnコルーチンを実行しているので、こちらに処理を追加していきます。
現状StartPlayerTurn関数の中身は以下のようになっています。
クリックで展開
if(battleActionDic[0] == BATTLEACTIONTYPE.NORMALATTACK)
{
SoundManager.instance.PlaySE(1);
commandUI.gameObject.SetActive(false);
commandUI.ShowDialogUI();
DialogTextManager.instance.SetScenarios(new string[] {
player.pname + "の攻撃!\n"});
yield return new WaitForSeconds(0.8f);
if (PlayerCheckHitAttack(targetIndex))
{
bool IsCritical = PlayerCheckCritical(targetIndex);
int damage = player.Attack(enemysList[targetIndex],IsCritical);
if (IsCritical)
{
SoundManager.instance.PlaySE(5);
DialogTextManager.instance.SetScenarios(new string[] {
"クリティカル!!\n" + enemysList[targetIndex].name + "に" + damage + "ダメージを与えた。" });
yield return new WaitForSeconds(0.8f);
}
else
{
DialogTextManager.instance.SetScenarios(new string[] {
enemysList[targetIndex].name + "に" + damage + "ダメージを与えた。" });
yield return new WaitForSeconds(0.8f);
}
enemysList[targetIndex].gameObject.GetComponent<EnemyUIManager>().UpdateUI(enemysList[targetIndex]);
}
else
{
SoundManager.instance.PlaySE(4);
DialogTextManager.instance.SetScenarios(new string[] {
enemysList[targetIndex].name + "に攻撃をかわされた。" });
yield return new WaitForSeconds(0.8f);
}
if (enemysList[targetIndex].hp <= 0)
{
yield return StartCoroutine(EnemyDeath(targetIndex));
if(CheckAllEnemyDeath())
{
yield return StartCoroutine(EndBattle());
}
}
上記のコメントで書いてある、"敵を倒した時の処理"より上は、通常攻撃を行った時の処理になるので、この処理を関数にしておきます。
クリックで展開
IEnumerator PlayerNormalAttack()
{
SoundManager.instance.PlaySE(1);
commandUI.gameObject.SetActive(false);
commandUI.ShowDialogUI();
DialogTextManager.instance.SetScenarios(new string[] {
player.pname + "の攻撃!\n"});
yield return new WaitForSeconds(0.8f);
if (PlayerCheckHitAttack(targetIndex))
{
bool IsCritical = PlayerCheckCritical(targetIndex);
int damage = player.Attack(enemysList[targetIndex], IsCritical);
if (IsCritical)
{
SoundManager.instance.PlaySE(5);
DialogTextManager.instance.SetScenarios(new string[] {
"クリティカル!!\n" + enemysList[targetIndex].name + "に" + damage + "ダメージを与えた。" });
yield return new WaitForSeconds(0.8f);
}
else
{
DialogTextManager.instance.SetScenarios(new string[] {
enemysList[targetIndex].name + "に" + damage + "ダメージを与えた。" });
yield return new WaitForSeconds(0.8f);
}
enemysList[targetIndex].gameObject.GetComponent<EnemyUIManager>().UpdateUI(enemysList[targetIndex]);
}
else
{
SoundManager.instance.PlaySE(4);
DialogTextManager.instance.SetScenarios(new string[] {
enemysList[targetIndex].name + "に攻撃をかわされた。" });
yield return new WaitForSeconds(0.8f);
}
}
この関数で処理を置き換え、BATTLEACTIONTYPEで処理を分けるとこんな感じになります。
クリックで展開
IEnumerator StartPlayerTurn()
{
switch (battleActionDic[0])
{
case BATTLEACTIONTYPE.NORMALATTACK:
yield return StartCoroutine(PlayerNormalAttack());
break;
case BATTLEACTIONTYPE.GUARD:
break;
case BATTLEACTIONTYPE.ITEM:
break;
case BATTLEACTIONTYPE.MAGIC:
break;
case BATTLEACTIONTYPE.MOVE:
break;
case BATTLEACTIONTYPE.ESCAPE:
break;
}
if (enemysList[targetIndex].hp <= 0)
{
yield return StartCoroutine(EnemyDeath(targetIndex));
if (CheckAllEnemyDeath())
{
yield return StartCoroutine(EndBattle());
}
}
}
これで行動タイプによって処理の分岐をするようになりました。
行動タイプITEMの場合の処理の実装
行動タイプがITEMの場合に実行される処理を実装していきます。
実際に実行させたい処理をItemEventから指定したいので、ここでは関数登録を使います。ItemEvent.csに関数登録用の変数とプレイヤーがアイテムを使うと決めた時に実行する関数を作成します。
クリックで展開
public UnityAction DecideUseItem;
public IEnumerator IEUseItemRegister;
public void DecidePlayerUseItemOnBattle()
{
commandUI.HideCancelButton();
itemUsePanel.gameObject.SetActive(false);
itemUIView.SetActive(false);
battleManager.playerItemEvent = this;
battleManager.SetPlayerBattleActionType(BattleManager.BATTLEACTIONTYPE.ITEM);
StartCoroutine(battleManager.TurnProcess());
}
DecideUseItem、IEUseItemRegisterへの関数の登録はItemUsePanelで行います。
クリックで展開
public void SetHealItemUsePanel(GameObject useItemMessagePanel,ItemData itemData,ItemUsePanel itemUsePanel)
{
var itemEvent = targetPartyMember.AddComponent<itemEvent>();
itemEvent.useItemMessaagePanel = useItemMessagePanel;
itemEvent.itemData = itemData;
itemEvent.itemUsePanel = itemUsePanel;
itemEvent.playerUIManager = this.playerUIManager;
itemEvent.cancelButton = cancelButton;
itemEvent.commandUI = this.commandUI;
itemEvent.itemCanvas = this.itemCanvas;
if (GameManager.instance.gamePhase == GameManager.GAMEPHASE.QUEST)
{
buttonState.onClick.AddListener(() => itemEvent.UseHealItem(PlayerManager.instance));
}else if (GameManager.instance.gamePhase == GameManager.GAMEPHASE.BATTLE)
{
buttonState.onClick.AddListener(() => itemEvent.DecidePlayerUseItemOnBattle());
itemEvent.DecideUseItem += battleManager.StartBattleTurn;
itemEvent.IEUseItemRegister = itemEvent.IEUseHealItemOnBattle();
}
}
Buttonを押した時の処理にDecidePlayerUseItemOnBattleを追加し、DecideUseItemにbattleManagerのStartBattleTurn関数、IEUseItemRegisterにIEUseHealItemOnBattleコルーチンを登録しました。
あとはアイテムを使った時にこれらの処理を実行されるようにBattleManagerに処理を書いていきます。
battleManagerでitemEventクラスのデータを保持できるように、itemEvent型の変数を作ります。
public itemEvent playerItemEvent;
PlayerのBATTLEACTIONTYPEがITEMの時に実行されるコルーチンを作成します。
クリックで展開
IEnumerator PlayerUseItem()
{
commandUI.gameObject.SetActive(false);
yield return StartCoroutine(playerItemEvent.IEUseItemRegister) ;
yield return null;
}
このコルーチンをStartPlayerTurnの中で呼び出します。
クリックで展開
IEnumerator StartPlayerTurn()
{
switch (battleActionDic[0])
{
case BATTLEACTIONTYPE.NORMALATTACK:
yield return StartCoroutine(PlayerNormalAttack());
break;
case BATTLEACTIONTYPE.GUARD:
break;
case BATTLEACTIONTYPE.ITEM:
yield return StartCoroutine(PlayerUseItem());
break;
case BATTLEACTIONTYPE.MAGIC:
break;
case BATTLEACTIONTYPE.MOVE:
break;
case BATTLEACTIONTYPE.ESCAPE:
break;
}
if (enemysList[targetIndex].hp <= 0)
{
yield return StartCoroutine(EnemyDeath(targetIndex));
if (CheckAllEnemyDeath())
{
yield return StartCoroutine(EndBattle());
}
}
}
あと1点バグ修正で、CommandUIManagerの
スクリプトのHideCancelButton関数を以下のように記述し直します。
クリックで展開
public void HideCancelButton()
{
cancelButton.SetActive(false);
cancelButton.gameObject.transform.Translate(0, 150, 0);
isOpenItemUI = false;
}
これを書いておかないと、PushItemButton関数のTranslateでY座標-150したキャンセルボタンがそのままになってしまいます。
この状態で実行すると以下の状況で問題が発生します。
BattleManagerのエラー発生箇所を確認するとif (enemysList[targetIndex].hp <= 0)となっています。
これは、攻撃した後に、攻撃対象のHPが0以下であれば敵をDestroyするという処理の判定箇所なのですが、このtargetIndexの値が、アイテムを使った場合元々の数値が入ったままで、前のターンのtargetindexが入っている状態です。敵を倒した場合、enemyListのint型の要素が削除されるようになっているのでエラーが出るのです。なので、敵を倒した時にtargetIndexの値をenemyListの存在するint型のKeyの値に変更します。
クリックで展開
IEnumerator EnemyDeath(int enemyIndex)
{
yield return new WaitForSeconds(0.5f);
SoundManager.instance.PlaySE(3);
enemysList[enemyIndex].enemyImage.transform.DOScale(new Vector3(2.0f, 2.0f, 2.0f), 1f);
enemysList[enemyIndex].enemyImage.DOColor(new Color(1f, 0f, 0f, 0f), 1f);
yield return new WaitForSeconds(2f);
DialogTextManager.instance.SetScenarios(new string[] {
enemysList[enemyIndex].name + "を倒した" });
yield return new WaitForSeconds(0.5f);
battleResult.AddGainGold(enemysList[targetIndex]);
battleResult.AddGainExp(enemysList[targetIndex]);
Debug.Log("enemysList[targetIndex]のオブジェクト破壊");
Destroy(enemysList[targetIndex].gameObject);
enemysList.Remove(key: targetIndex);
Debug.Log("enemysListの要素数は" + enemysList.Count);
DeletAgiDicElemDeathEnemy(targetIndex);
Debug.Log("AgiDicの要素数は" + AgiDic.Count);
if(enemysList.Count != 0)
{
targetIndex = enemysList.First().Key;
}
}
enemysList.First().KeyでenemysListのDictionaryに存在する一番最初に見つけた要素のint型のKeyを取得できます。これでもう1回実行してみます。
youtu.be