【Unity】RPG制作 その3 -プレイヤーの情報作成
今回はプレイヤーのステータスまわりを実装していく。
まずはじめに、プレイヤーの管理を行っているスクリプト"PlayerManager.cs"にプレイヤーのステータスを追加する。
追加前のスクリプト
クリックで展開
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerManager : MonoBehaviour { public int hp; public int sp; public int at; //攻撃する public int Attack(EnemyManager enemy) { int damage = enemy.Damage(at); return damage; } //ダメージを受ける public int Damage(int damage) { hp -= damage; if (hp <= 0) { hp = 0; } return damage; } }
追加後のスクリプト
クリックで展開
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerManager : MonoBehaviour { //-----------New-------------- public string name; //主人公の名前 public int hp; //HP public int tp; //TP(特殊技に必要) public int at; //攻撃力 public int def; //防御力 public int agi; //速さ public int luk; //運の良さ public int sence; //感覚の鋭さ public int hitRate; //命中率 public int evasionRate; //回避率 public int criticalRate; //クリティカル率 New public int itemCapacity; //持てるアイテムの容量 //-----------Newここまで------- //攻撃する public int Attack(EnemyManager enemy) { float calcDamage = at - enemy.def / 4f;//プレイヤーの攻撃力-(エネミーの防御力/4) New calcDamage = calcDamage * UnityEngine.Random.Range(1.0f - 0.2f, 1.0f + 0.2f);//ダメージに-20%から+20%の幅をもたせる New if (isCritical) calcDamage *= 2; //New int damage = enemy.Damage((int)calcDamage);//計算した値をenemyのダメージ関数に渡す New return damage; } //ダメージを受ける public int Damage(int damage) { hp -= damage; if (hp <= 0) { hp = 0; } return damage; } }
取り敢えず使いそうなステータスを追加。Attack関数にエネミーの防御力をクリティカルかどうかを計算に入れるようにした。
次にエネミーの方にもステータスを追加する。
追加前のスクリプト
クリックで展開
using System; using UnityEngine; using DG.Tweening; //敵を管理するもの(ステータス/クリック検出) public class EnemyManager : MonoBehaviour { //関数登録 Action tapAction; //クリックされた時に実行したい関数(外部から設定したい) public new string name; public int hp; public int at; public GameObject hitEffect; private void Start() { } //攻撃する public int Attack(PlayerManager player) { int damage = player.Damage(at); return damage; } //ダメージを受ける public int Damage(int damage) { Instantiate(hitEffect, this.transform, false); transform.DOShakePosition(0.3f,0.5f,20,0,false,true); hp -= damage; if(hp <= 0) { hp = 0; } return damage; } // tapActionに関数を登録する関数を作る public void AddEventListenerOnTap(Action action) { tapAction += action; } public void OnTap() { tapAction(); } }
追加後のスクリプト
クリックで展開
using System; using UnityEngine; using DG.Tweening; //敵を管理するもの(ステータス/クリック検出) public class EnemyManager : MonoBehaviour { //関数登録 Action tapAction; //クリックされた時に実行したい関数(外部から設定したい) //-----------New-------------- public new string name; //名前 public int hp; //HP public int tp; //TP public int at; //攻撃力 public int def; //防御力 public int agi; //速さ public int luk; //運の良さ public int hitRate; //命中率 public int evasionRate; //回避率 public int criticalRate; //クリティカル率 //New //-----------Newここまで------- public GameObject hitEffect; private void Start() { } //攻撃する public int Attack(PlayerManager player) { float calcDamage = at - player.def / 4f;//エネミーの攻撃力-(プレイヤーの防御力/4) New calcDamage = calcDamage * UnityEngine.Random.Range(1.0f - 0.2f, 1.0f + 0.2f);//ダメージに-20%から+20%の幅をもたせる New if (isCritical) calcDamage *= 2; //New int damage = player.Damage((int)calcDamage);//計算した値をplayerのダメージ関数に渡す New return damage; } //ダメージを受ける public int Damage(int damage) { Instantiate(hitEffect, this.transform, false); transform.DOShakePosition(0.3f,0.5f,20,0,false,true); hp -= damage; if(hp <= 0) { hp = 0; } return damage; } // tapActionに関数を登録する関数を作る public void AddEventListenerOnTap(Action action) { tapAction += action; } public void OnTap() { tapAction(); } }
こちらもPlayerManagerと同様にAttack関数に防御力とクリティカルを計算に入れるように。
次に攻撃時に命中判定、クリティカル判定を行うようにする。
BattleManager.csを編集していきます。
変更後のスクリプト
クリックで展開
using System.Collections; using System.Collections.Generic; using UnityEngine; using DG.Tweening; //PlayerとEnemyの対戦の管理 public class BattleManager : MonoBehaviour { public Transform playerDamagePanel; public QuestManager questManager; public PlayerUIManager playerUI; public EnemyUIManager enemyUI; public CommandUIManager commandUI; public PlayerManager player; EnemyManager enemy; private bool canAttackTap; //攻撃のタップが出来るかどうか(連打防止) private void Start() { enemyUI.gameObject.SetActive(false); //StartCoroutine(SampleCol()); playerUI.SetupUI(player); } //サンプルコルーチン /* IEnumerator SampleCol() { Debug.Log("コルーチン開始"); yield return new WaitForSeconds(2f); Debug.Log("2秒経過"); } */ public void SetUp(EnemyManager enemyManager) { SoundManager.instance.PlayBGM("Battle"); enemyUI.gameObject.SetActive(true); enemy = enemyManager; enemyUI.SetupUI(enemy); playerUI.SetupUI(player); //canAttackTap = true; commandUI.gameObject.SetActive(true); commandUI.SetBattleCommand(); enemy.AddEventListenerOnTap(PlayerAttack); //enemy.transform.DOMove(new Vector3(0,10,0), 5f); } public void PlayerAttack() { if (canAttackTap) //攻撃タップ可能であれば { StopAllCoroutines(); StartCoroutine(StartPlayerAttack()); } } IEnumerator StartPlayerAttack() { SoundManager.instance.PlaySE(1); commandUI.gameObject.SetActive(false); canAttackTap = false; //取り敢えず攻撃メッセージ DialogTextManager.instance.SetScenarios(new string[] { player.pname + "の攻撃!\n"}); yield return new WaitForSeconds(1.2f); //1.2秒間待ってから以後の処理を実行 if (CheckHitAttack(true))//命中したら { bool IsCritical = CheckCritical(true); int damage = player.Attack(enemy,IsCritical); if (IsCritical) { SoundManager.instance.PlaySE(5); //クリティカル時SE再生 DialogTextManager.instance.SetScenarios(new string[] { "クリティカル!!\n" + enemy.name + "に" + damage + "ダメージを与えた。" }); } else { DialogTextManager.instance.SetScenarios(new string[] { enemy.name + "に" + damage + "ダメージを与えた。" }); } enemyUI.UpdateUI(enemy); } else { SoundManager.instance.PlaySE(4); //回避時SE再生 DialogTextManager.instance.SetScenarios(new string[] { enemy.name + "に攻撃をかわされた。" }); } if (enemy.hp <= 0) { StartCoroutine(EndBattle()); } else { StartCoroutine(EnemyTurn()); } } IEnumerator EnemyTurn() { yield return new WaitForSeconds(2f); //2秒間待ってから以後の処理を実行 SoundManager.instance.PlaySE(1);//攻撃のSE DialogTextManager.instance.SetScenarios(new string[] { enemy.name + "の攻撃!\n" }); yield return new WaitForSeconds(1.2f); //1.2秒間待ってから以後の処理を実行 if (CheckHitAttack(false))//命中したら { playerDamagePanel.DOShakePosition(0.3f, 0.5f, 20, 0, false, true); //0.3秒かけて画面を揺らす bool isCritical = CheckCritical(false); int damage = enemy.Attack(player,isCritical); //敵の攻撃関数 if (isCritical) { SoundManager.instance.PlaySE(5); //クリティカル時SE再生 DialogTextManager.instance.SetScenarios(new string[] { "クリティカル!!\n" + player.pname + "に" + damage + "ダメージを与えた。" }); } else { DialogTextManager.instance.SetScenarios(new string[] { player.pname + "に" + damage + "ダメージを与えた。" }); } playerUI.UpdateUI(player); } else { SoundManager.instance.PlaySE(4); //回避時SE再生 DialogTextManager.instance.SetScenarios(new string[] { player.pname + "は攻撃をかわした。" }); } yield return new WaitForSeconds(1f); if (player.hp <= 0) { // playerが死んだ場合の実装 questManager.PlayerDeath(); } else { //そうでなければ戦闘続行。敵の攻撃が終わって再びプレイヤーが行動できるようになる commandUI.gameObject.SetActive(true); commandUI.SetBattleCommand();//バトルコマンドのUIをセット } } IEnumerator EndBattle() { yield return new WaitForSeconds(2f); SoundManager.instance.PlaySE(3); enemy.transform.DOScale(new Vector3(2.0f, 2.0f, 2.0f), 1f); SpriteRenderer enemySpriteRenderer = enemy.GetComponent<SpriteRenderer>(); //enemySpriteRenderer.DOFade(0, 1f); enemySpriteRenderer.DOColor(new Color(1f, 0f, 0f, 0f), 1f); //徐々に赤く、透明にする(敵撃破演出) yield return new WaitForSeconds(2f);//敵撃破演出に1秒時間がかかるので余裕を見て2秒処理を待つ DialogTextManager.instance.SetScenarios(new string[] { enemy.name + "を倒した" }); enemyUI.gameObject.SetActive(false); Destroy(enemy.gameObject); SoundManager.instance.PlayBGM("Quest"); enemyUI.gameObject.SetActive(false); questManager.EndBattle(); } public bool CanAttackProperty //プロパティ(未使用) { get { return canAttackTap; } set { canAttackTap = value; } } public void SetCanAttackTap(bool canTap) { canAttackTap = canTap; } public bool CheckCritical(bool isPlayerAttack) { int calcCriticalRate; if (isPlayerAttack) { calcCriticalRate = (int)((player.criticalRate + (player.hitRate / 10.0f) + (player.luk / 10.0f)) - ((enemy.evasionRate / 30.0f) + (enemy.luk / 20.0f))); if (calcCriticalRate >= UnityEngine.Random.Range(1, 101)) { return true; } else { return false; } } else { calcCriticalRate = (int)((enemy.criticalRate + (enemy.luk / 10.0f)) - ((player.evasionRate / 30.0f) + (player.luk / 20.0f))); if (calcCriticalRate >= UnityEngine.Random.Range(1, 101)) { return true; } else { return false; } } } public bool CheckHitAttack(bool isPlayerAttack) { int calcHitRate; if (isPlayerAttack) { calcHitRate = (int)((player.hitRate + (player.sence / 10.0f) + (player.luk / 50.0f)) - (enemy.evasionRate + (enemy.agi / 10.0f) + (enemy.luk / 20.0f))); if (calcHitRate >= UnityEngine.Random.Range(1, 101)) { return true; } else { return false; } } else { calcHitRate = (int)((enemy.hitRate + (enemy.agi / 10.0f) + (enemy.luk / 50.0f)) - (player.evasionRate + (player.agi / 10.0f) + (player.luk / 20.0f))); if (calcHitRate >= UnityEngine.Random.Range(1, 101)) { return true; } else { return false; } } } }
196行目CheckCritical、228CheckHitAttackでそれぞれクリティカルかどうか、命中したかどうかを判定している。
命中判定は攻撃側の命中率、受け側の回避率以外も影響するステータスがあるようにしています(微々たるものだが)。
あとはSoundManagerに回避時とクリティカル時のSEを設定する。
今回は以上です。