【Unity】RPG制作 その27-プレイヤーの属性耐性値・状態異常のかかりやすさの値の確認画面作成
今回はプレイヤーの属性耐性値・状態異常のかかりやすさの値を確認できる画面を作成していきたいと思います。これらの画面はプレイヤーのステータス画面で表示させたいので、画面を切り替えるためのボタンをPlayerStatusUICanvas内に配置します。
属性耐性値を表示するUIを作成していきます。とりあえずテキストで属性耐性値を出力したいので以下の画像のように作成します。
今回、属性耐性値をレーダーグラフで表示させたいので、以下のサイトを参考にしながらレーダーグラフを作っていきます。
https://blog.naichilab.com/entry/radarchart
レーダーグラフを描画するのに必要なクラスを2つ作成します。クラス名はRadarChartPolygonUGUIクラスとRadarChartLineUGUIクラスです。それぞれ以下のように記述します。
クリックで展開
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using System; namespace naichilab { /// <summary> /// レーダーチャートのポリゴンを描画 /// </summary> public class RadarChartPolygonUGUI : Graphic { /// <summary> /// 描画半径 /// </summary> const float RADIUS = 0.5f; [Header("General")] [SerializeField] [Range(3, 30)] private int VerticesCount = 5; [SerializeField] [Range(0f, 1f)] private float MaxVolume = 1f; [SerializeField] private float[] Volumes; private void SetVolume(int idx, float value) { if (this.Volumes.Length < idx) { Array.Resize(ref this.Volumes, idx + 1); } this.Volumes[idx] = value; } private float GetVolume(int idx) { if (Volumes.Length - 1 < idx) { return 0; } float v = this.Volumes[idx]; return v > this.MaxVolume ? this.MaxVolume : v; } protected override void OnPopulateMesh(VertexHelper vh) { vh.Clear(); var v = UIVertex.simpleVert; v.color = color; Vector2 center = CreatePos(0.5f, 0.5f); v.position = center; vh.AddVert(v); //各頂点座標 for (int i = 1; i <= VerticesCount; i++) { float rad = (90f - (360f / (float)VerticesCount) * (i - 1)) * Mathf.Deg2Rad; float x = 0.5f + Mathf.Cos(rad) * RADIUS * GetVolume(i - 1); float y = 0.5f + Mathf.Sin(rad) * RADIUS * GetVolume(i - 1); Vector2 p = CreatePos(x, y); v.position = p; vh.AddVert(v); vh.AddTriangle( 0, i, i == VerticesCount ? 1 : i + 1 ); } } private Vector2 CreatePos(float x, float y) { Vector2 p = Vector2.zero; p.x -= rectTransform.pivot.x; p.y -= rectTransform.pivot.y; p.x += x; p.y += y; p.x *= rectTransform.rect.width; p.y *= rectTransform.rect.height; return p; } } }
クリックで展開
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; namespace naichilab { /// <summary> /// レーダーチャートの罫線を描画 /// </summary> public class RadarChartLineUGUI : Graphic { /// <summary> /// 描画半径 /// </summary> const float RADIUS = 0.5f; [Header("General")] [SerializeField] [Range(3, 30)] private int VerticesCount = 5; [SerializeField] [Range(0f, 1f)] private float MaxVolume = 1f; [SerializeField] [Tooltip("線の太さ")] [Range(0.001f, 0.03f)] private float LineWidth = 0.02f; [Header("Major Grid")] [SerializeField] [Tooltip("主罫線を表示するかどうか")] private bool DrawMajorGrid = true; [SerializeField] [Range(0.01f, 1f)] [Tooltip("主罫線の間隔")] private float MajorGridInterval = 0.2f; protected override void OnPopulateMesh(VertexHelper vh) { vh.Clear(); if (this.MaxVolume == 0) return; var v = UIVertex.simpleVert; v.color = color; //Outer Frame this.DrawFrame(vh, this.MaxVolume); //Axis this.DrawAxis(vh, this.MaxVolume); //Major Grid if (this.DrawMajorGrid && this.MajorGridInterval < this.MaxVolume) { int numOfGrid = (int)(this.MaxVolume / this.MajorGridInterval); for (int i = 1; i <= numOfGrid; i++) { this.DrawFrame(vh, i * this.MajorGridInterval); } } } /// <summary> /// uGUI座標を作成 /// </summary> private Vector2 CreatePos(float x, float y) { Vector2 p = Vector2.zero; p.x -= rectTransform.pivot.x; p.y -= rectTransform.pivot.y; p.x += x; p.y += y; p.x *= rectTransform.rect.width; p.y *= rectTransform.rect.height; return p; } /// <summary> /// 外周を描画 /// </summary> private void DrawFrame(VertexHelper vh, float vol) { int currentVertCount = vh.currentVertCount; var v = UIVertex.simpleVert; v.color = color; //各頂点座標 for (int i = 0; i < VerticesCount; i++) { float deg = (360f / VerticesCount) * 0.5f; float offset = (this.LineWidth / Mathf.Cos(deg * Mathf.Deg2Rad)) / 2f; float rad = (90f - (360f / (float)VerticesCount) * i) * Mathf.Deg2Rad; float x1 = 0.5f + Mathf.Cos(rad) * (RADIUS * vol - offset); float y1 = 0.5f + Mathf.Sin(rad) * (RADIUS * vol - offset); float x2 = 0.5f + Mathf.Cos(rad) * (RADIUS * vol + offset); float y2 = 0.5f + Mathf.Sin(rad) * (RADIUS * vol + offset); Vector2 p1 = CreatePos(x1, y1); Vector2 p2 = CreatePos(x2, y2); v.position = p1; vh.AddVert(v); v.position = p2; vh.AddVert(v); vh.AddTriangle( (((i + 0) * 2) + 0) % (VerticesCount * 2) + currentVertCount, (((i + 0) * 2) + 1) % (VerticesCount * 2) + currentVertCount, (((i + 1) * 2) + 0) % (VerticesCount * 2) + currentVertCount ); vh.AddTriangle( (((i + 1) * 2) + 0) % (VerticesCount * 2) + currentVertCount, (((i + 0) * 2) + 1) % (VerticesCount * 2) + currentVertCount, (((i + 1) * 2) + 1) % (VerticesCount * 2) + currentVertCount ); } } /// <summary> /// 軸を描画 /// </summary> private void DrawAxis(VertexHelper vh, float vol) { int currentVertCount = vh.currentVertCount; var v = UIVertex.simpleVert; v.color = color; for (int i = 0; i < VerticesCount; i++) { float halfWidthDeg = 90 * this.LineWidth / (Mathf.PI * RADIUS * vol); float rad1 = (90f - halfWidthDeg - (360f / (float)VerticesCount) * i) * Mathf.Deg2Rad; float rad2 = (90f + halfWidthDeg - (360f / (float)VerticesCount) * i) * Mathf.Deg2Rad; float x3 = 0.5f + Mathf.Cos(rad1) * RADIUS * vol; float y3 = 0.5f + Mathf.Sin(rad1) * RADIUS * vol; float x4 = 0.5f + Mathf.Cos(rad2) * RADIUS * vol; float y4 = 0.5f + Mathf.Sin(rad2) * RADIUS * vol; float x1 = 0.5f + (x3 - x4) / 2f; float y1 = 0.5f + (y3 - y4) / 2f; float x2 = 0.5f + (x4 - x3) / 2f; float y2 = 0.5f + (y4 - y3) / 2f; Vector2 p1 = CreatePos(x1, y1); Vector2 p2 = CreatePos(x2, y2); Vector2 p3 = CreatePos(x3, y3); Vector2 p4 = CreatePos(x4, y4); v.position = p1; vh.AddVert(v); v.position = p2; vh.AddVert(v); v.position = p3; vh.AddVert(v); v.position = p4; vh.AddVert(v); vh.AddTriangle( ((i * 4) + 0) + currentVertCount, ((i * 4) + 3) + currentVertCount, ((i * 4) + 2) + currentVertCount ); vh.AddTriangle( ((i * 4) + 0) + currentVertCount, ((i * 4) + 1) + currentVertCount, ((i * 4) + 3) + currentVertCount ); } } } }
属性耐性値を表示するパネルRegiElementListオブジェクトの階層下にPanelを新規作成し、Panelの階層下に新規のオブジェクトを2つ作成し、名前をRadarChartPolygonUGUI,RadarChartLineUGUIにし、同名のスクリプトを貼り付けます。
グラフの値や線の太さなどを適当に調整し、アイコンを配置して外見を作ります。
同様にして状態異常有効率表も作りました。
それぞれの表を制御するコードをPlayerStatusUI.csに記述していきます。
クリックで展開
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using naichilab;//new public class PlayerStatusUI : MonoBehaviour { public GameObject StatusList;//New public GameObject RegiElementList; //New public GameObject RegiCondiList; //New public Button RButton; //New public Button LButton; //New public RadarChartPolygonUGUI elementRadarChart;//New public RadarChartPolygonUGUI condiRadarChart;//New //--------------New------------------------- //--------ステータス表で表示するテキスト--------- public Text nameText; public Text hpText; public Text mpText; public Text tpText; public Text atkText; public Text defText; public Text agiText; public Text lukText; public Text senceText; public Text magpowText; public Text magdefText; public Text learnAbiText; //-------属性有効率表で表示するテキスト----------- public Text normalText; public Text fireText; public Text windText; public Text groundText; public Text thunderText; public Text aquaText; public Text iceText; public Text lightText; public Text darkText; public Text dragonText; public Text soundText; public Text starText; public Text allText; //--------------------------------------------- //------状態異常有効率表で表示するテキスト-------- public Text poisonText; public Text blindText; public Text paralysisText; public Text sleepText; public Text confusionText; public Text burnText; public Text frozenText; public Text wetText; //------------------------------------------- //--------------------Newここまで---------------------- public enum ListType //New { STATUS,//ステータス表 REGIELEMENT,//属性有効率表 REGICONDI,//状態抵抗値表 } ListType nowList = ListType.STATUS;//現在表示しているリストのタイプ public void Start() { RegiElementList.SetActive(false); //New RegiCondiList.SetActive(false); //New this.gameObject.SetActive(false); } public void SetStatusText() { nameText.text = "名前 " + PlayerManager.instance.pname; hpText.text = "HP " + PlayerManager.instance.hp + " / " + PlayerManager.instance.afterEquipStatusValue[GeneralEnum.STATUS.HP] + "(" + PlayerManager.instance.baseStatusValue[GeneralEnum.STATUS.HP] + ")"; mpText.text = "MP " + PlayerManager.instance.mp + " / " + PlayerManager.instance.afterEquipStatusValue[GeneralEnum.STATUS.MP] + "(" + PlayerManager.instance.baseStatusValue[GeneralEnum.STATUS.MP] + ")"; tpText.text = "TP " + PlayerManager.instance.tp; atkText.text = "攻撃 " + PlayerManager.instance.afterEquipStatusValue[GeneralEnum.STATUS.ATK] + "(" + PlayerManager.instance.baseStatusValue[GeneralEnum.STATUS.ATK] + ")"; defText.text = "防御 " + PlayerManager.instance.afterEquipStatusValue[GeneralEnum.STATUS.DEF] + "(" + PlayerManager.instance.baseStatusValue[GeneralEnum.STATUS.DEF] + ")"; agiText.text = "速さ " + PlayerManager.instance.afterEquipStatusValue[GeneralEnum.STATUS.AGI] + "(" + PlayerManager.instance.baseStatusValue[GeneralEnum.STATUS.AGI] + ")"; lukText.text = "運 " + PlayerManager.instance.afterEquipStatusValue[GeneralEnum.STATUS.LUK] + "(" + PlayerManager.instance.baseStatusValue[GeneralEnum.STATUS.LUK] + ")"; senceText.text = "感覚 " + PlayerManager.instance.afterEquipStatusValue[GeneralEnum.STATUS.SENCE] + "(" + PlayerManager.instance.baseStatusValue[GeneralEnum.STATUS.SENCE] + ")"; magpowText.text = "魔力 " + PlayerManager.instance.afterEquipStatusValue[GeneralEnum.STATUS.MAGPOW] + "(" + PlayerManager.instance.baseStatusValue[GeneralEnum.STATUS.MAGPOW] + ")"; magdefText.text = "魔防 " + PlayerManager.instance.afterEquipStatusValue[GeneralEnum.STATUS.MAGDEF] + "(" + PlayerManager.instance.baseStatusValue[GeneralEnum.STATUS.MAGDEF] + ")"; learnAbiText.text = "習得 " + PlayerManager.instance.afterEquipStatusValue[GeneralEnum.STATUS.LEARNABI] + "(" + PlayerManager.instance.baseStatusValue[GeneralEnum.STATUS.LEARNABI] + ")"; } public void SetElementText() //New { normalText.text = "無 " + PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.NONE]; fireText.text = "火 " + PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.FIRE]; windText.text = "風 " + PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.WIND]; groundText.text = "大地 " + PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.GROUND]; thunderText.text = "雷 " + PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.THUNDER]; aquaText.text = "水 " + PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.AQUA]; iceText.text = "氷 " + PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.ICE]; lightText.text = "光 " + PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.LIGHT]; darkText.text = "闇 " + PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.DARK]; dragonText.text = "龍 " + PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.DRAGON]; soundText.text = "音 " + PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.SOUND]; starText.text = "星 " + PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.STAR]; allText.text = "全 " + PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.ALL]; } public void SetCondiText() //New { poisonText.text = "毒 " + PlayerManager.instance.afEqResistanceOfStatusValue[GeneralEnum.STATUSCONDITION.POISON]; blindText.text = "盲目 " + PlayerManager.instance.afEqResistanceOfStatusValue[GeneralEnum.STATUSCONDITION.BLIND]; paralysisText.text = "麻痺 " + PlayerManager.instance.afEqResistanceOfStatusValue[GeneralEnum.STATUSCONDITION.PARALYSIS]; sleepText.text = "睡眠 " + PlayerManager.instance.afEqResistanceOfStatusValue[GeneralEnum.STATUSCONDITION.SLEEP]; confusionText.text = "混乱 " + PlayerManager.instance.afEqResistanceOfStatusValue[GeneralEnum.STATUSCONDITION.CONFUSION]; burnText.text = "燃焼 " + PlayerManager.instance.afEqResistanceOfStatusValue[GeneralEnum.STATUSCONDITION.BURN]; frozenText.text = "凍結 " + PlayerManager.instance.afEqResistanceOfStatusValue[GeneralEnum.STATUSCONDITION.FROZEN]; wetText.text = "水濡れ " + PlayerManager.instance.afEqResistanceOfStatusValue[GeneralEnum.STATUSCONDITION.WET]; } public void ShowStatusUI() //変更 { SoundManager.instance.PlaySE(22); this.gameObject.SetActive(true); switch (nowList) { case ListType.STATUS: ShowStatusList(); break; case ListType.REGIELEMENT: ShowRegiElementList(); break; default: break; } } public void HideStatuUI() { SoundManager.instance.PlaySE(7); this.gameObject.SetActive(false); } public void ShowStatusList() //New { SoundManager.instance.PlaySE(22); SetStatusText(); RegiElementList.gameObject.SetActive(false); RegiCondiList.gameObject.SetActive(false); StatusList.gameObject.SetActive(true); } public void HideStatusList() { SoundManager.instance.PlaySE(7); StatusList.gameObject.SetActive(false); } public void ShowRegiElementList()//New { SoundManager.instance.PlaySE(22); SetElementText(); SetElementRadarGraphValue(); StatusList.gameObject.SetActive(false); RegiCondiList.gameObject.SetActive(false); RegiElementList.gameObject.SetActive(true); } public void HideRegiElementList() //New { SoundManager.instance.PlaySE(7); RegiElementList.gameObject.SetActive(false); } public void ShowRegiCondiList() { SoundManager.instance.PlaySE(22); SetCondiText(); SetCondiRadarGraphValue(); StatusList.gameObject.SetActive(false); RegiElementList.gameObject.SetActive(false); RegiCondiList.gameObject.SetActive(true); } public void PushRButton() //New { switch (nowList) { case ListType.STATUS: ShowRegiElementList(); nowList = ListType.REGIELEMENT; break; case ListType.REGIELEMENT: ShowRegiCondiList(); nowList = ListType.REGICONDI; break; case ListType.REGICONDI: ShowStatusList(); nowList = ListType.STATUS; break; } } public void PushLButton() //New { switch (nowList) { case ListType.STATUS: ShowRegiCondiList(); nowList = ListType.REGICONDI; break; case ListType.REGIELEMENT: ShowStatusList(); nowList = ListType.STATUS; break; case ListType.REGICONDI: ShowRegiElementList(); nowList = ListType.REGIELEMENT; break; } } /// <summary> /// 属性耐性値のグラフの値をセットする /// </summary> public void SetElementRadarGraphValue()//New { int RegiValue; RegiValue = PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.NONE]; RegiValue = 400 - RegiValue;//(400が耐性皆無、0が完全な耐性、-100で吸収する) elementRadarChart.Volumes[0] = RegiValue / 500f; RegiValue = PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.FIRE]; RegiValue = 400 - RegiValue; elementRadarChart.Volumes[1] = RegiValue / 500f; RegiValue = PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.WIND]; RegiValue = 400 - RegiValue; elementRadarChart.Volumes[2] = RegiValue / 500f; RegiValue = PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.GROUND]; RegiValue = 400 - RegiValue; elementRadarChart.Volumes[3] = RegiValue / 500f; RegiValue = PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.THUNDER]; RegiValue = 400 - RegiValue; elementRadarChart.Volumes[4] = RegiValue / 500f; RegiValue = PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.AQUA]; RegiValue = 400 - RegiValue; elementRadarChart.Volumes[5] = RegiValue / 500f; RegiValue = PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.ICE]; RegiValue = 400 - RegiValue; elementRadarChart.Volumes[6] = RegiValue / 500f; RegiValue = PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.LIGHT]; RegiValue = 400 - RegiValue; elementRadarChart.Volumes[7] = RegiValue / 500f; RegiValue = PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.DARK]; RegiValue = 400 - RegiValue; elementRadarChart.Volumes[8] = RegiValue / 500f; RegiValue = PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.DRAGON]; RegiValue = 400 - RegiValue; elementRadarChart.Volumes[9] = RegiValue / 500f; RegiValue = PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.SOUND]; RegiValue = 400 - RegiValue; elementRadarChart.Volumes[10] = RegiValue / 500f; RegiValue = PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.STAR]; RegiValue = 400 - RegiValue; elementRadarChart.Volumes[11] = RegiValue / 500f; RegiValue = PlayerManager.instance.afEqResistanceOfElementValue[GeneralEnum.ELEMENT.ALL]; RegiValue = 400 - RegiValue; elementRadarChart.Volumes[12] = RegiValue / 500f; } /// <summary> /// 状態異常有効率のグラフの値をセットする /// </summary> public void SetCondiRadarGraphValue()//New { int RegiValue; RegiValue = PlayerManager.instance.afEqResistanceOfStatusValue[GeneralEnum.STATUSCONDITION.POISON]; RegiValue = 200 - RegiValue; condiRadarChart.Volumes[0] = RegiValue / 200f; RegiValue = PlayerManager.instance.afEqResistanceOfStatusValue[GeneralEnum.STATUSCONDITION.BLIND]; RegiValue = 200 - RegiValue; condiRadarChart.Volumes[1] = RegiValue / 200f; RegiValue = PlayerManager.instance.afEqResistanceOfStatusValue[GeneralEnum.STATUSCONDITION.PARALYSIS]; RegiValue = 200 - RegiValue; condiRadarChart.Volumes[2] = RegiValue / 200f; RegiValue = PlayerManager.instance.afEqResistanceOfStatusValue[GeneralEnum.STATUSCONDITION.SLEEP]; RegiValue = 200 - RegiValue; condiRadarChart.Volumes[3] = RegiValue / 200f; RegiValue = PlayerManager.instance.afEqResistanceOfStatusValue[GeneralEnum.STATUSCONDITION.CONFUSION]; RegiValue = 200 - RegiValue; condiRadarChart.Volumes[4] = RegiValue / 200f; RegiValue = PlayerManager.instance.afEqResistanceOfStatusValue[GeneralEnum.STATUSCONDITION.BURN]; RegiValue = 200 - RegiValue; condiRadarChart.Volumes[5] = PlayerManager.instance.afEqResistanceOfStatusValue[GeneralEnum.STATUSCONDITION.BURN] / 200f; RegiValue = PlayerManager.instance.afEqResistanceOfStatusValue[GeneralEnum.STATUSCONDITION.FROZEN]; RegiValue = 200 - RegiValue; condiRadarChart.Volumes[6] = PlayerManager.instance.afEqResistanceOfStatusValue[GeneralEnum.STATUSCONDITION.FROZEN] / 200f; RegiValue = PlayerManager.instance.afEqResistanceOfStatusValue[GeneralEnum.STATUSCONDITION.WET]; RegiValue = 200 - RegiValue; condiRadarChart.Volumes[7] = PlayerManager.instance.afEqResistanceOfStatusValue[GeneralEnum.STATUSCONDITION.WET] / 200f; } }
それぞれの表自体のゲームオブジェクトとテキスト、レーダーグラフの値をセットする関数にRButton,LButtonを押した時に表を切り替える処理を記述しました。公開変数とButtonのOnclickに各々の設定をして実行すると以下の動画のようになります。
次回は戦闘中の能力値周りを実装していきます。