ゲーム化!tomo_manaのブログ

ゲーム化!tomo-manaのブログ

Unityでゲームを作る方法について紹介しています

Unity×会計#1 貸借対照表のフォーマット (Unity 2019.4.4f1)

f:id:tomo_mana:20211220002058p:plain

今回は、RectTransform と Layout を使って、貸借対照表のフォーマットを作成します。

参考

bookmeter.com
貸借対照表の各項の合計だけを抽出した「箱型バランスシート」が分かりやすそうなので、参考にさせて頂きました。「現金」「流動資産」「流動負債」「固定資産」「固定負債」「純資産」の6項目で構成します。

貸借対照表(バランスシート)の変化を追うと簡単に投資銘柄の業績が把握できる | 1億人の投資術


貸借対照表

図と名称
和名 英名
現金 Cash
流動/固定資産 Flexible/Fixed Assets
流動/固定負債 Flexible/Fixed Liabilities
純資産 Net Assets

Hierarchy

今回は RectTransfrom で表現します。

構成

f:id:tomo_mana:20210727001711p:plain
Hierarchy - BalanceSheet

BalanceSheet、Assets、Liabilities は Empty Object、Cash などは Panel で作成し、Text(TextMeshPro) をぶら下げています。

レイアウト

BalanceSheet (HorizontalLayoutGroup)

貸借対照表は資産の部(左)と負債/純資産の部(右)に分かれるため、Width方向を拘束します。

f:id:tomo_mana:20210727000856p:plain
BalanceSheet - HorizontalLayoutGroupの設定
Assets/Liabilities (VerticalLayoutGroup)

資産の部、負債/純資産の部の中身は縦に整列させるため、height方向を拘束します。

f:id:tomo_mana:20210727000953p:plain
Assets/Liabilities - VerticalLayoutGroup の設定

フォント

商用・埋め込み許可フォントから選びました。
りいてがきN:フリーフォント

[Project] Assets > Fonts ディレクトリを作成
[Menu] Window > TextMeshPro > FontAssetCreator
設定は以下の通り

f:id:tomo_mana:20210805215835p:plain
TextMeshPro - FontAssetCreator の設定

※最初は常用漢字+JIS第一・第二水準まで出力してみたのですが、アトラスに入りきらないので、やっぱり最低限の文字出力でいくことにしました。

あとは各Panelに張り付けていきます。

各パネルの設定

アライメント、色

分かりやすいように、流動資産、流動負債、純資産に色を付けます。それぞれ青、赤、黄色とします。
Panel > Image > Color
●赤(255, 64, 0)
●青(0, 64, 255)
●黄色(255, 255, 32)

フォントの設定

先ほど作成した日本語の文字を割り当てます。
TextMeshPro > Font Asset
先ほどのFont Asset Creatorで作成したSDFファイルを選択

純資産の計算

最後に、純資産が正か負かを判別する計算式を作ります。ついでに、各項目に金額を入れます。
作成したコードを、BalanceSheet ゲームオブジェクトのコンポーネントとして追加します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;

public class BalanceSheet : MonoBehaviour
{
    // 貸借対照表の主要な項目
    enum BS_AREA {
        BS_CASH = 0,// 現金
        BS_FLA,     // 流動資産
        BS_FIA,     // 固定資産
        BS_NAN,     // 純資産(負)
        BS_FLL,     // 流動負債
        BS_FIL,     // 固定負債
        BS_NAP,     // 純資産
        BS_MAX
    };
    
    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;
    }
    
    private 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;
    }
    
    // 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];                  //初期値リストから取得
        }
        
        // 資産と負債の合計を計算
        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;
        
        // 箱の比率を計算
        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];
        }
        
        // 箱の大きさを比率に応じて更新
        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;
            }
        }
    }
}

表示テスト

f:id:tomo_mana:20210805220153p:plain
バランスシート出力テスト

ゲームのURL(前回と同じURLです)
tomo-mana.hatenablog.com

次回

入力フィールドを作成して、任意の値に変更できるようにします。