ゲーム化!tomo_manaのブログ

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

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

Unity×会計#4 損益計算書 (Unity 2019.4.4f1)

f:id:tomo_mana:20211220005911p:plain

今回は、貸借対照表を作成します。

第2回の損益計算書とセットで使うので、利益/損失を上に書きます。

f:id:tomo_mana:20210811002921p:plain
決算仕訳(イメージ)

Hierarchy

損益計算書は、収益と利益は言葉が似ていて混乱しやすいですが、収益が売上、利益が売上と仕入の差額です。

英訳について、以下のサイトを参考に、収益をRevenue、利益をNet Incomeとしています。
英文会計でBSとPLの関係《ゼロから学ぶ英文国際会計実務セミナー資料解説 RI-Studies》

ゲームオブジェクトは以下のように配置しました。

f:id:tomo_mana:20210814134348p:plain
Hierarchy - ProfitAndLoss

配置は、第2回貸借対照表と同じく、各項目をPanelで作成し、LayoutGroupを適用するためにEmpty Objectでくくっています。貸借対照表と比べると以下のような感じです。

f:id:tomo_mana:20210814185536p:plain
Hierarchy - BalanceSheetとの対比

損(Loss)、益(Profit)各欄はEmpty Objectで、VerticalLayoutGroupを適用しています。

f:id:tomo_mana:20210814193255p:plain
Loss、Profit - VerticalLayoutGroupの設定

また、損益両欄をくくるEmpty Objectである損益計算書(ProfitAndLoss)もEmpty Objectで、HorizontalLayoutGroupを適用しています。

f:id:tomo_mana:20210814193340p:plain
ProfitAndLoss - HorizontalLayoutGroupの設定

損益計算書のコードは、貸借対照表のコードを流用して作ります。以下のコードをProfitAndLossオブジェクトに追加します。

コード

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

// 損益計算書の主要な項目
public enum PL_AREA {
    PL_EXP = 0, // 費用
    PL_INC,     // 利益 自動計算
    PL_REV,     // 収益
    PL_LOS,     // 損失 自動計算
    PL_MAX
};

public class ProfitAndLoss : MonoBehaviour
{
    public struct PlAreaId {
        public int plArea;
        public string goName;
        
        public PlAreaId(int id, string name)
        {
            this.plArea = id;
            this.goName = name;
        }
    }
    
    private PlAreaId[] plAreaId = {
        new PlAreaId( (int)(PL_AREA.PL_EXP), "Expenses" ),
        new PlAreaId( (int)(PL_AREA.PL_INC), "NetIncome" ),
        new PlAreaId( (int)(PL_AREA.PL_REV), "Revenue" ),
        new PlAreaId( (int)(PL_AREA.PL_LOS), "NetLoss" ),
    };
    
    public struct PlArea {
        public GameObject go;
        public TextMeshProUGUI textArea;
        public string areaName;
        public int value;
        public float rate;
    }
    
    private int[] plAreaDefVal = {
        8000,       // 費用
        0,          // 利益 自動計算
        10000,      // 収益
        0,          // 損失 自動計算
    };
    
    GameObject[] children;
    Component[] components;
    TextMeshProUGUI tmpobj;
    PlArea[] plArea = new PlArea[4];
    
    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( PL_AREA id, int val )
    {
        if( plArea[(int)id].value != val){
            plArea[(int)id].value = val;
            RedrawProfitAndLoss();
        }
    }
    
    private void RedrawProfitAndLoss()
    {
        int i;
        
        // 資産と負債の合計を計算
        int[] sum = new int[3];
        sum[0] = plArea[(int)(PL_AREA.PL_EXP)].value;  // 費用
        sum[1] = plArea[(int)(PL_AREA.PL_REV)].value;  // 収益
        
        // 純資産の向きと大きさを計算
        if( sum[0] < sum[1] ){
            sum[2] = sum[1];
        } else {
            sum[2] = sum[0];
        }
        plArea[(int)(PL_AREA.PL_LOS)].value = sum[2] - sum[1];
        plArea[(int)(PL_AREA.PL_INC)].value = sum[2] - sum[0];
        
        // 領域ごとの金額(表示)を更新
        for( i = 0; i < (int)(PL_AREA.PL_MAX); i++ )
        {
            plArea[i].textArea.text = plArea[i].areaName + "\n" + plArea[i].value;
        }
        
        // 貸借対照表の大きさ(今回は固定)
        int height = 100;
        
        // 箱の比率を計算
        if( sum[2] != 0 ){
            for( i = 0; i < (int)(PL_AREA.PL_INC); i++ )
            {
                plArea[i].rate = (float)plArea[i].value / sum[2];
            }
            for( i = (int)(PL_AREA.PL_INC); i < (int)(PL_AREA.PL_MAX); i++ )
            {
                plArea[i].rate = (float)plArea[i].value / sum[2];
            }
        } else {
            for( i = 0; i < (int)(PL_AREA.PL_MAX); i++ ){
                plArea[i].rate = 0;
            }
        }
        
        // 箱の大きさを比率に応じて更新
        RectTransform rt;
        Vector2 v;
        for( i = 0; i < (int)(PL_AREA.PL_MAX); i++ )
        {
            if( plArea[i].rate == 0 ){
                plArea[i].go.SetActive(false);
            } else {
                plArea[i].go.SetActive(true);
                rt = (RectTransform)plArea[i].go.transform;
                v = rt.sizeDelta;
                v.y = plArea[i].rate * height;
                rt.sizeDelta = v;
            }
        }
    }
    
    // Start is called before the first frame update
    void Start()
    {
        // 領域初期化
        int i;
        for( i = 0; i < (int)(PL_AREA.PL_MAX); i++ )
        {
            plArea[i].go = GameObject.Find( plAreaId[i].goName );
            plArea[i].textArea = GetTextArea( plArea[i].go );   //TextMeshProから取得
            plArea[i].areaName = plArea[i].textArea.text;   //TextMeshProから取得
            plArea[i].value = plAreaDefVal[i];                  //初期値リストから取得
        }
        RedrawProfitAndLoss();
    }
}

動作テスト

f:id:tomo_mana:20210814141810p:plain
表示テスト

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

次回

第4回で作った仕訳ボタンに、初期化と決済のボタンを追加して、仕入・売上が損益計算書貸借対照表に反映されるようにします。