今回は、前回作った貸借対照表に入力フィールドを追加して、金額を変更できるようにします。
前回の内容
前回は、貸借対照表をRectTransformで作成しました。
(作成された貸借対照表)
貸借対照表の各項の合計だけを抽出した「箱型バランスシート」が分かりやすそうなので、参考にさせて頂いています。「現金」「流動資産」「流動負債」「固定資産」「固定負債」「純資産」の6項目で構成します。
bookmeter.com
入力フィールドの作成
純資産を除く貸借対照表の各項目を変更できる入力フィールドを作ります。Text(説明文)、InputField(入力値)、Button(設定ボタン)で構成します。
オブジェクトの追加
Text、InputField、Buttonを追加します。文字列はすべてTextMeshPro を使用します。さらにEmpty Objectでくくります(ここではInputLineという名前にします)。
Empty Object(InputLine)に HorizontalLayoutGroupを設定します。
各テキストのフォント・サイズを調整後、Prefabにします。
Prefabにした入力フィールドを5つ複製、Empty Objectでくくります(ここではInputWindowという名前にします)。
Empty Object(InputWindow)には、VerticalLayoutGroupを設定します。
コードと関連付け
入力フィールドのコードの作り方はいくつか選択肢がありますが、今回は手抜きして、全部のPrefabを一つのコードで制御します。
貸借対照表との関連付け
入力フィールドは貸借対照表のテスト的な存在なので、入力フィールドが一方的に貸借対照表を参照するように作ります。(入力フィールドを切り離しても貸借対照表を使えるようにする)
(図)
入力フィールド (InputWindow)
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using TMPro; public class InputWindow : MonoBehaviour { [SerializeField] BalanceSheet bs; public struct InputLine { public TMP_InputField field; } InputLine[] inputLine = new InputLine[5]; int GetBsAreaVal(int id) { if( (id < 0) || (5 < id) ){ return 0; } if( ReferenceEquals(bs, null) ){ return 0; } if( id >= 3 ){ id++; } return bs.BsAreaDefVal[id]; } void ButtonClicked(int buttonNo) { if( ReferenceEquals(bs, null) ){ return; } int id = buttonNo; if( id >= 3 ){ id++; } int v; if( int.TryParse( inputLine[buttonNo].field.text, out v ) ){ bs.ChangeAreaValue( (BS_AREA)id, int.Parse(inputLine[buttonNo].field.text) ); } } // Start is called before the first frame update void Start() { int i = 0; Button button; // InputFieldゲームオブジェクトを取得 foreach( Transform child in gameObject.transform ){ inputLine[i].field = child.Find("InputField (TMP)").GetComponent<TMP_InputField>(); // デフォルト値をフィールド初期値に設定 inputLine[i].field.text = GetBsAreaVal(i).ToString(); button = child.Find("Button").GetComponent<Button>(); int ii = i; button.onClick.AddListener(() => ButtonClicked(ii)); i++; } } }
貸借対照表(BalanceSheet)
前回のコードの一部を再描画処理(RedrawBalanceSheet)として抜き出して、入力フィールドから値が設定された(ChangeAreaValue)ときに再描画するようにします。
using System.Collections; using System.Collections.Generic; using UnityEngine; using TMPro; // 貸借対照表の主要な項目 public enum BS_AREA { BS_CASH = 0,// 現金 BS_FLA, // 流動資産 BS_FIA, // 固定資産 BS_NAN, // 純資産(負) BS_FLL, // 流動負債 BS_FIL, // 固定負債 BS_NAP, // 純資産 BS_MAX }; public class BalanceSheet : MonoBehaviour { public struct BsAreaId { public int bsArea; public string goName; public BsAreaId(int id, string name) { this.bsArea = id; this.goName = name; } } private BsAreaId[] bsAreaId = { new BsAreaId( (int)(BS_AREA.BS_CASH), "Cash" ), new BsAreaId( (int)(BS_AREA.BS_FLA), "FlexibleAssets" ), new BsAreaId( (int)(BS_AREA.BS_FIA), "FixedAssets" ), new BsAreaId( (int)(BS_AREA.BS_NAN), "NetAssetsL" ), new BsAreaId( (int)(BS_AREA.BS_FLL), "FlexibleLiabilities" ), new BsAreaId( (int)(BS_AREA.BS_FIL), "FixedLiabilities" ), new BsAreaId( (int)(BS_AREA.BS_NAP), "NetAssetsR" ), }; //ポインタ、名前、金額 public struct BsArea { public GameObject go; public TextMeshProUGUI textArea; public string areaName; public int value; public float rate; } int[] BsAreaDefVal = { 10000, // 現金 25000, // 流動資産 20000, // 固定資産 0, // 純資産(負) 自動計算 8000, // 流動負債 25000, // 固定負債 0, // 純資産 自動計算 }; GameObject[] children; Component[] components; TextMeshProUGUI tmpobj; BsArea[] bsArea = new BsArea[7]; TextMeshProUGUI GetTextArea( GameObject obj ) { if( obj == null ){ return null; } foreach( Transform child in obj.transform ){ tmpobj = child.gameObject.GetComponent<TextMeshProUGUI>(); if( tmpobj != null ){ return tmpobj; } } return null; } public void ChangeAreaValue( BS_AREA id, int val ) { if( bsArea[(int)id].value != val){ bsArea[(int)id].value = val; RedrawBalanceSheet(); } } private void RedrawBalanceSheet() { int i; // 資産と負債の合計を計算 int[] sum = new int[3]; sum[0] = bsArea[(int)(BS_AREA.BS_CASH)].value + bsArea[(int)(BS_AREA.BS_FLA)].value + bsArea[(int)(BS_AREA.BS_FIA)].value; // 資産 sum[1] = bsArea[(int)(BS_AREA.BS_FLL)].value + bsArea[(int)(BS_AREA.BS_FIL)].value; // 負債 // 純資産の向きと大きさを計算 if( sum[0] < sum[1] ){ sum[2] = sum[1]; } else { sum[2] = sum[0]; } bsArea[(int)(BS_AREA.BS_NAP)].value = sum[2] - sum[1]; bsArea[(int)(BS_AREA.BS_NAN)].value = sum[2] - sum[0]; // 領域ごとの金額(表示)を更新 for( i = 0; i < (int)(BS_AREA.BS_MAX); i++ ) { bsArea[i].textArea.text = bsArea[i].areaName + "\n" + bsArea[i].value; } // 貸借対照表の大きさ(今回は固定) int height = 300; // 箱の比率を計算 if( sum[2] != 0 ){ for( i = 0; i < (int)(BS_AREA.BS_FLL); i++ ) { bsArea[i].rate = (float)bsArea[i].value / sum[2]; } for( i = (int)(BS_AREA.BS_FLL); i < (int)(BS_AREA.BS_MAX); i++ ) { bsArea[i].rate = (float)bsArea[i].value / sum[2]; } } else { for( i = 0; i < (int)(BS_AREA.BS_MAX); i++ ){ bsArea[i].rate = 0; } } // 箱の大きさを比率に応じて更新 RectTransform rt; Vector2 v; for( i = 0; i < (int)(BS_AREA.BS_MAX); i++ ) { if( bsArea[i].rate == 0 ){ bsArea[i].go.SetActive(false); } else { bsArea[i].go.SetActive(true); rt = (RectTransform)bsArea[i].go.transform; v = rt.sizeDelta; v.y = bsArea[i].rate * height; rt.sizeDelta = v; } } } // Start is called before the first frame update void Start() { // 領域初期化 int i; for( i = 0; i < (int)(BS_AREA.BS_MAX); i++ ) { bsArea[i].go = GameObject.Find( bsAreaId[i].goName ); bsArea[i].textArea = GetTextArea( bsArea[i].go ); //TextMeshProから取得 bsArea[i].areaName = bsArea[i].textArea.text; //TextMeshProから取得 bsArea[i].value = BsAreaDefVal[i]; //初期値リストから取得 } RedrawBalanceSheet(); } }
動作テスト
ゲームのURL(前回までと同じURLです)
tomo-mana.hatenablog.com
次回
現金取引の仕分けを追加します。
参考
TextMeshPro の InputField
TMP_InputFieldで参照します(TextMeshProUGUIと異なるクラス)。
inputFieldのTMP版をスクリプトで使う方法。 - Qiita
null比較
== null でなく、ReferenceEquals(object, object)を使用しました。
GameObjectやComponentをnullと比較するときの落し穴 - Qiita