【Unity】RPG制作 その11- アイテム使用処理(探索中)
RPG制作その4とその5でアイテムのUIと所持数の処理は実装したのですが、実際に使う処理をまだ実装していないので、今回はアイテム使用処理を実装していきます。
今回かなり煩雑な内容になっています。参考程度に御覧ください。
現在のゲームの場面に応じて処理が分けられるように、GameManagerでGAMEPHASEという名前で列挙型定数を宣言します。
クリックで展開
using System.Collections; using System.Collections.Generic; using UnityEngine; public class GameManager : MonoBehaviour { //シングルトン(すべてのシーンで共有する)) public static GameManager instance; private void Awake() { if (instance == null) { instance = this; DontDestroyOnLoad(this.gameObject); } else { Destroy(this.gameObject); } } //--シングルトン終わり-- public int gold; [System.NonSerialized] public int partyMemberCount = 1; //パーティの人数 New //現在のゲームフェーズの列挙型 public enum GAMEPHASE //New { TOWN, QUEST, BATTLE, }; [System.NonSerialized] public GAMEPHASE gamePhase = GAMEPHASE.TOWN; }
そして、探索の開始時(街から探索に出た時)、戦闘に突入した時、戦闘が終わって探索に戻る時、探索が終わって街に戻る時にgamePhaseを変更します。
クリックで展開
GameManager.instance.gamePhase = GameManager.GAMEPHASE.QUEST; // ゲームフェーズをQUESTに New stageUI.UpdateUI(currentStage); commandUI.gameObject.SetActive(false); DialogTextManager.instance.SetScenarios(new string[] { "洞窟についた。"}); playerUIManager.SetupUI(PlayerManager.instance);
クリックで展開
void EncountEnemy() { GameManager.instance.gamePhase = GameManager.GAMEPHASE.BATTLE; // ゲームフェーズをBATTLEに New stageUI.HideButtons(); commandUI.gameObject.SetActive(true); battleManager.SetUpBattle(); //EnemyGroupの中からランダムに敵グループを生成する //敵のプレハブを配列からランダムに生成する int randomEnemyGroupID = Random.Range(0, enemyGroupList.enemyGroup.Length); enemyGroup = enemyGroupList.enemyGroup[randomEnemyGroupID]; enemyObjs.Clear(); EnemyManager enemy; for (int i = 0; i < enemyGroup.enemys.Length; i++) { enemyObjs.Add(Instantiate(enemyGroup.enemys[i])); enemy = enemyObjs[i].GetComponent<EnemyManager>(); battleManager.SetEnemy(i,enemy); float posX = enemyObjs[i].GetComponent<EnemyUIManager>().SetXPosition(enemyGroup.enemys.Length, i); enemyObjs[i].transform.position = new Vector3(posX, 0.0f, 0.0f); enemyObjs[i].GetComponent<EnemyUIManager>().SetupUI(enemy);//敵のプレハブが保持しているUIのセット New } }
クリックで展開
public void EndBattle() { GameManager.instance.gamePhase = GameManager.GAMEPHASE.QUEST; // ゲームフェーズをQUESTに New commandUI.gameObject.SetActive(false); stageUI.ShowButtons(); }
クリックで展開
public IEnumerator GotoTown() //New { GameManager.instance.gamePhase = GameManager.GAMEPHASE.TOWN; // ゲームフェーズをTOWNに New yield return new WaitForSeconds(0.1f); sceneTransisitonManager.LoadTo("Town"); }
それからアイテムの個別の効果を設定するItemDataスクリプトのenum STATUSCONDITIONとPlayerManagerのenum STATUSCONDITIONを共用したいので、どちらもGeneralEnum型に宣言し直します。
クリックで展開
using System.Collections; using System.Collections.Generic; using UnityEngine; public class GeneralEnum { public enum STATUS //New { HP, MP, ATK, DEF, AGI, LUK, SENCE, MAGPOW, MAGDEF, LEARNABI, } public enum STATUSCONDITION { DEAD, POISON, //毒 (毎ターンダメージ。戦闘が終わっても治らない。) BLIND, //盲目(通常攻撃の命中率大幅ダウン(3分の1)) PARALYSIS, //麻痺(数ターン身動きができない。魔法の詠唱は出来る。) SLEEP, //睡眠(数ターン行動できない。攻撃を受けると高確率で起きる。) CONFUSION, //混乱 (数ターン敵味方判別せずに通常攻撃する。敵から攻撃を受けると解除する時がある。) BURN, //燃焼 FROZEN, //凍結 (数ターン動けない) ATKUP, //攻撃力UP DEFUP, //防御力UP AGIUP, //速さUP LUKUP, //運の良さUP HITRATEUP, //命中率UP EVASIONRATEUP, //回避率UP CRITICALRATEUP, //クリティカル率UP MAGPOWUP, //魔力UP MAGDEFUP, //魔法防御力UP ATKDOWN, //攻撃力DOWN DEFDOWN, //防御力DOWN AGIDOWN, //速さDOWN LUKDOWN, //運の良さDOWN HITRATEDOWN, //命中率DOWN EVASIONRATEDOWN, //回避率DOWN CRITICALRATEDOWN, //クリティカル率DOWN MAGPOWDOWN, //魔力DOWN MAGDEFDOWN, //魔法防御力DOWN } }
PlayerManagerとItemDataのもともとSTATUSCONDITIONだった部分の前にGeneralEnum.をつけて置き換えます。
これでSTATUSCONDITIONをスクリプト間で共有できるようになりました。
それでは今からアイテムの使用処理の実装をしていきます。今回は探索中に回復アイテムが使用できるようにしていきます。
ItemUIのアイテムの項目をタップした時に、使用するターゲットを選択する為のパネルと、アイテム使用時にテキストを表示するためのパネルを作成します。ItemUICanvasの階層下にPanelオブジェクトを2つ作成し、それぞれ名前をItemUsePanel,UseItemMessageとします。そしてスクリプト、”ItemUsePanel”を新規作成し、ItemUsePanelオブジェクトに貼り付けます。
ItemUsePanel.csを開き、以下のように記述します。
クリックで展開
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class ItemUsePanel : MonoBehaviour { public PlayerUIManager playerUIManager; public GameObject itemCanvas; public GameObject itemUI; public GameObject cancelButton; public bool canTapItemUsePanel = true; public void SetHealItemUsePanel(GameObject useItemMessagePanel,ItemData itemData,ItemUsePanel itemUsePanel) { ResetItemUsePanel(); for (int i = 0; i < GameManager.instance.partyMemberCount; i++) { GameObject targetPartyMember = new GameObject("PartyMember" + (i + 1).ToString()); targetPartyMember.transform.parent = this.transform; //ItemUsePanelオブジェクトを親にする var Rect = targetPartyMember.AddComponent<RectTransform>(); Rect.transform.localPosition = new Vector3(0 ,0 ,0 ); Rect.transform.localScale = new Vector3(1, 1, 1); Rect.sizeDelta = new Vector3(0,100); targetPartyMember.AddComponent<CanvasRenderer>(); targetPartyMember.AddComponent<Image>(); targetPartyMember.AddComponent<LayoutElement>().preferredHeight = 100; var buttonState = targetPartyMember.AddComponent<Button>(); //背景の色を変えて見やすく var colors = buttonState.colors; if (this.transform.childCount % 2 == 0) { colors.normalColor = new Color(0F / 255F, 0F / 255F, 0F / 255F, 128F / 255F); colors.highlightedColor = new Color(0F / 255F, 0F / 255F, 0F / 255F, 128F / 255F); colors.pressedColor = new Color(0F / 255F, 0F / 255F, 0F / 255F, 128F / 255F); colors.disabledColor = new Color(0F / 255F, 0F / 255F, 0F / 255F, 128F / 255F); } else { colors.normalColor = new Color(0 / 255F, 0 / 255F, 0 / 255F, 50 / 255F); colors.highlightedColor = new Color(0 / 255F, 0 / 255F, 0 / 255F, 50 / 255F); colors.pressedColor = new Color(0 / 255F, 0 / 255F, 0 / 255F, 50 / 255F); colors.disabledColor = new Color(0 / 255F, 0 / 255F, 0 / 255F, 50 / 255F); } buttonState.colors = colors; GameObject text = new GameObject("Item" + (i + 1).ToString()); text.transform.parent = targetPartyMember.transform; var rect = text.AddComponent<RectTransform>(); rect.transform.localPosition = new Vector3(0, 0, 0); rect.transform.localScale = new Vector3(1,1,1); rect.sizeDelta = new Vector2(900, 90); text.AddComponent<CanvasRenderer>(); var textChild = text.AddComponent<Text>(); //----------------プレイヤー名のテキスト生成----------- textChild.text = PlayerManager.instance.pname; textChild.color = new Color(255f / 255f, 255f / 255f, 255f / 255f, 255f / 255f); textChild.fontSize = 30; textChild.alignment = TextAnchor.MiddleCenter; textChild.font = Resources.GetBuiltinResource(typeof(Font), "Arial.ttf") as Font; //-----------ボタンを押したときの処理------ var itemEvent = targetPartyMember.AddComponent<itemEvent>(); itemEvent.useItemMessaagePanel = useItemMessagePanel; itemEvent.itemData = itemData; itemEvent.itemUsePanel = itemUsePanel; itemEvent.playerUIManager = this.playerUIManager; itemEvent.cancelButton = cancelButton; itemEvent.itemCanvas = this.itemCanvas; buttonState.onClick.AddListener(() => itemEvent.UseHealItem(PlayerManager.instance)); ; } } public void SetAttackItemUsePanel() { } public void ResetItemUsePanel() { if(this.gameObject.transform.childCount != 0) { foreach(Transform child in this.gameObject.transform) { //パネルの要素を全て削除する Destroy(child.gameObject); } } } }
リストの作り方はItemUIと同じで、項目の生成個数をGameManagerのint型変数のPartyMemberCountの数にしています。現在はPlayer一人だけなので個数を1にしています。パネルの下に生成したゲームオブジェクトにItemEventクラス(今回新規作成するクラス)をAddComponentし、ItemEventクラスの関数をonclickに登録しています。
新規作成したitemEvent.csの中身はこんな感じです。
クリックで展開
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; //アイテムUIでButtonコンポーネント付きのオブジェクトにアタッチするスクリプト //各アイテムの処理を行う public class itemEvent : MonoBehaviour { ItemManager itemManager; public ItemData itemData; public GameObject itemCanvas; public ItemUsePanel itemUsePanel; public ItemUI itemUI; public GameObject itemUIView; public GameObject useItemMessaagePanel; public Text useItemText; TermManager termManagerF; public PlayerUIManager playerUIManager; public GameObject cancelButton; void Start() { itemManager = GameObject.Find("ItemManager").GetComponent<ItemManager>();//階層上の"ItemManager"を取得 itemUI = GameObject.Find("ItemUISystem").GetComponent<ItemUI>(); itemUIView = GameObject.Find("ItemUI_Scroll View"); termManagerF = new TermManager(); } // Update is called once per frame void Update() { } public void SetItemTargetPanel() { Debug.Log(itemUI); if (itemUI.GetComponent<ItemUI>().canTapItemUI) { itemUI.GetComponent<ItemUI>().canTapItemUI = false; useItemText = useItemMessaagePanel.transform.GetChild(0).GetComponent<Text>(); if (GameManager.instance.gamePhase == GameManager.GAMEPHASE.QUEST) //ゲームフェーズがQUESTの場合 { if (itemData.canUseScene == ItemData.AVAILABLESCENES.BATTLEONLY)//戦闘時のみ使用可の場合は使えない { SoundManager.instance.PlaySE(11); return; } if (itemData.itemType == ItemData.ITEMTYPE.HEAL) //回復アイテムの場合の処理 { // とりあえず使用対象がプレイヤーに対してと仮定してスクリプトを組む itemUsePanel.gameObject.SetActive(true); //itemUI.SetActive(false); itemUsePanel.SetHealItemUsePanel(useItemMessaagePanel, itemData, itemUsePanel); } else if (itemData.itemType == ItemData.ITEMTYPE.BOOKOFMAGIC) //魔導書アイテムの場合 { itemUsePanel.gameObject.SetActive(true); //itemUI.SetActive(false); } } else if (GameManager.instance.gamePhase == GameManager.GAMEPHASE.BATTLE) { if (itemData.canUseScene == ItemData.AVAILABLESCENES.QUESTONLY) { SoundManager.instance.PlaySE(11); return; } if (itemData.itemType == ItemData.ITEMTYPE.HEAL) //回復アイテムの場合の処理 { // とりあえず使用対象がプレイヤーに対してと仮定してスクリプトを組む itemUsePanel.gameObject.SetActive(true); //itemUI.SetActive(false); itemUsePanel.SetHealItemUsePanel(useItemMessaagePanel, itemData, itemUsePanel); } else if (itemData.itemType == ItemData.ITEMTYPE.ATTACK) { itemUsePanel.gameObject.SetActive(true); //itemUI.SetActive(false); itemUsePanel.SetAttackItemUsePanel(); } } } } public void UseHealItem(PlayerManager player) { if (itemUsePanel.canTapItemUsePanel) { itemUsePanel.canTapItemUsePanel = false; StartCoroutine(IEUseHealItem(player)); } } //回復アイテムを使用したときの処理(状態異常治療も含む) public IEnumerator IEUseHealItem(PlayerManager player) { useItemMessaagePanel.SetActive(true); useItemText = useItemMessaagePanel.transform.GetChild(0).GetComponent<Text>(); Debug.Log(useItemText); useItemText.text = player.pname + "は" + itemData.itemName + "を使った!"; yield return new WaitForSeconds(0.5f); SoundManager.instance.PlaySE(itemData.UseSEID);//アイテム使用SE yield return new WaitForSeconds(0.7f); useItemText.text = ""; yield return new WaitForSeconds(0.5f); //回復アイテムの回復量を計算する(最大HP * 回復割合 + 固定回復量) int hpPoint = (int)(player.maxHp * itemData.HPHealRateValue + itemData.healHPPoint); int mpPoint = (int)(player.maxMp * itemData.MPHealRateValue + itemData.healMPPoint); int tpPoint = (int)(player.maxTp * itemData.TPHealRateValue + itemData.healTPPoint); bool wasItemEffective = false; player.hp += hpPoint; player.mp += mpPoint; player.tp += tpPoint; if(player.hp > player.maxHp) { hpPoint -= player.hp - player.maxHp; //回復量をテキストに出力するために計算 player.hp = player.maxHp; } if(hpPoint > 0) { useItemText.text = player.pname + "のHPが" + hpPoint + "回復した!"; SoundManager.instance.PlaySE(12);//回復SE yield return StartCoroutine(MessageWait1()); wasItemEffective = true; } if (player.mp > player.maxMp) { mpPoint -= player.mp - player.maxMp; player.mp = player.maxMp; } if(mpPoint > 0) { useItemText.text = player.pname + "のMPが" + mpPoint + "回復した!"; SoundManager.instance.PlaySE(12); yield return StartCoroutine(MessageWait1()); wasItemEffective = true; } if (player.tp > player.maxTp) { tpPoint -= player.tp - player.maxTp; player.tp = player.maxTp; } if(tpPoint > 0) { useItemText.text = player.pname + "のTPが" + tpPoint + "回復した!"; SoundManager.instance.PlaySE(12); yield return StartCoroutine(MessageWait1()); wasItemEffective = true; } //探索用の特殊効果実装部分(未実装) if(itemData.tempQuestBuff1 == ItemData.QUESTBUFF.AVOIDENEMIES) { } if (itemData.tempQuestBuff2 == ItemData.QUESTBUFF.AVOIDENEMIES) { } if (itemData.tempQuestBuff3 == ItemData.QUESTBUFF.AVOIDENEMIES) { } //アイテムの個数を1減らす itemManager.itemCountDictionary[itemData.itemID] -= 1; if (!wasItemEffective) { useItemText.text = "しかし何もおこらなかった"; yield return new WaitForSeconds(1.2f); } playerUIManager.UpdateUI(PlayerManager.instance); CloseItemMessageAndPanel(); LikePushCancelButton(); } public void CloseItemMessageAndPanel() { itemUI.canTapItemUI = true; itemUsePanel.canTapItemUsePanel = true; useItemMessaagePanel.SetActive(false); itemUsePanel.gameObject.SetActive(false); itemUIView.SetActive(true); } public void LikePushCancelButton() //キャンセルボタンが押された時の挙動をitemEventで実行 New { cancelButton.GetComponent<Button>().onClick.Invoke(); } }
このItemEventクラスには、ItemUIの項目がタップされた時に実行されるSetItemTargetPanelと、ItemUsePanelの項目がタップされた時に実行される(回復アイテムの場合は)UseHealItemを定義しています。UseHealItemは先程のItemUsePanelの項目のonclickで実装しました。次はItemUIの項目のonclickにSetItemTargetPanelを登録します。ItemUI.csのSetItemUI関数の以下の部分で記述します。
クリックで展開
//ボタンを押したときの処理に関連するitemEventコンポーネントを付ける var itemEvent = Contents.AddComponent<itemEvent>(); itemEvent.itemData = itemManager.itemDatas[i]; itemEvent.itemUsePanel = itemUsePanel; itemEvent.useItemMessaagePanel = useItemMessagePanel; buttonState.onClick.AddListener(itemEvent.SetItemTargetPanel); //New //-----------イベントここまで
これでitemUIのアイテムの項目が押された時にアイテムの使用者を選択するパネルが表示され、実際にそのパネルで対象を選ぶ(今回はPlayerのみですが)と、実際にアイテムの効果を使用対象に及ぼすことができるようになりました。
ついでにデバッグ用のUIも作成しておきました。
今回は以上です。