Unityに関連する記事です

情報の管理方法

入れ子クラスの作成と配列(List)の初期化


 2つ以上のデータを1つの情報内にまとめて管理したい場合、クラスや構造体を作成すると管理しやすくなります。
他のクラスでの利用がなければ、新しいスクリプト・ファイルを作成するのではなく、利用したいクラス内で入れ子クラスとして宣言しておく方が
利用箇所の特定、および隠蔽の双方においてメリットがあります。

 管理したい情報2つだけの情報で、片方の情報をラベル代わりに利用し、中身を1つだけ保持したいケースでは Dictionary が利用できます。


入れ子クラスの宣言


 入れ子クラスはクラスの継承が行えないという制約があります。
そのため new したタイミングでメンバ変数内に値を代入したい場合にはコンストラクタ・メソッドを用意しておきます。
コンストラクタは引数のオーバーロード機能が利用できますので、複数のコンストラクタを用意しておくことで、状況に応じて使い分けることが可能です。

    public class InfoData {
        public string message;
        public Color32 imageColor;

        /// <summary>
        /// コンストラクタ M囘咾鮓堕蠅靴親端譴淵灰鵐好肇薀タ
        /// </summary>
        public InfoData() {
            // オブジェクト初期化子を使う場合には、空っぽのコンストラクタが必要になります
        }

        /// <summary>
        /// コンストラクタ◆0貳姪なコンストラクタ
        /// 引数のオーバーロード機能を使い、コンストラクタを2つ用意します
        /// </summary>
        /// <param name="str"></param>
        /// <param name="color"></param>
        public InfoData(string str, Color32 color) {
            message = str;
            imageColor = color;
        }
    }


配列として管理する方法

メンバ変数の宣言時の初期化


        // 配列の場合(この変数自体はメンバ変数で用意しておきます)
        InfoData[] infoDatas;

        // メンバ変数の宣言時に初期化する場合(メソッド内でも書けます)
        // この処理にはコンストラクタ△鰺用しています。
        InfoData[] infoDatas = new InfoData[dataCount] {
            new InfoData("Remove", new Color32(255, 31, 0, 150)), 
            new InfoData( "Put", new Color32(0, 246, 67, 150))
        };


通常の初期化


 メンバ変数の宣言時に初期化を行わない場合、メソッド内で初期化を行うことになります。
その場合の初期化の方法は2種類あります

 こちらの初期化の方法は、コンストラクタ△鰺用した、通常の初期化の方法です。

  //まずサイズを設定します
  infoDatas = new InfoData[dataCount];

  // 値を代用します
  infoDatas[0] = new InfoData("Remove", new Color32(255, 31, 0, 150));
 infoDatas[1] = new InfoData("Put", new Color32(0, 246, 67, 150));


オブジェクト初期化子


 こちらの初期化の方法はオブジェクト初期化子を用いた方法です

 この方法は、コンストラクタを何も用意しないか、あるいは今回のようにコンストラクタを用意した場合には
引数のオーバーロード機能を利用し、,鉢△裡欧弔離灰鵐好肇薀タを用意します
そのうちの,離灰鵐好肇薀タを利用しています

  //まずサイズを設定します
  infoDatas = new InfoData[dataCount];

  // 値を代用します
  infoDatas[0] = new InfoData { message = "Remove", imageColor = new Color32(255, 31, 0, 150) };
  infoDatas[1] = new InfoData { message = "Put", imageColor = new Color32(0, 246, 67, 150) };


List として管理する方法


 List の場合(この変数自体はメンバ変数で宣言して用意しておきます)

  List<InfoData> infoDataList;

  List<InfoData> infoDataList = new List<InfoData>();

  List<InfoData> infoDataList = new ();


通常の初期化


 List の場合、サイズの指定は不要なので、そのまま追加します。
Add メソッドを利用して初期化(追加)する方法の場合は、コンストラクタ△鮖箸辰討い泙
丁寧に書く場合、変数に代入してから Add します。この場合、変数としてその後も利用できます。

        // ここから、メソッド内の処理になります(メンバ変数の宣言時に new しておいてもよいです)
        infoDataList = new List<InfoData>();

        InfoData infoData = new InfoData("Remove", new Color32(255, 31, 0, 150));
        infoDataList.Add(infoData);
            
        // 変数を利用する必要がない場合には、Add 内で直接インスタンスして追加します
        infoDataList.Add(new InfoData("Put", new Color32(0, 246, 67, 150)));


コレクション初期化子


 List では下記のような初期化の方法も出来ます。
この初期化の方法をコレクション初期化子といいます
この方法もコンストラクタ△鮖箸辰討い泙

 なおこちらの処理は変数の宣言時にも利用できます

        infoDataList = new List<InfoData>
        {
           new InfoData("Remove", new Color32(255, 31, 0, 150)),
           new InfoData("Put", new Color32(0, 246, 67, 150))
        };


Dictionary として管理する方法


 今回は利用しませんが、同じくコレクションである Dictionary の使い方も書いておきます

        // Dictionary の場合(この変数自体はメンバ変数で用意しておきます)
        Dictionary<string, Color32> infoDataDic;

        // Add メソッドを利用する場合
        // このケースでは List と違い、コンストラクタは不要です
        infoDataDic = new Dictionary<string, Color32>();
        infoDataDic.Add("Remove", new Color32(255, 31, 0, 150));
        infoDataDic.Add("Put", new Color32(0, 246, 67, 150));


コレクション初期化子


        // コレクション初期化子を利用した初期化の場合
        // こちらもコンストラクタは不要です
        // List と同様に変数の宣言時にも利用できます
        infoDataDic = new Dictionary<string, Color32> {
            { "Remove", new Color32(255, 31, 0, 150) },
            { "Put", new Color32(0, 246, 67, 150) }
        };


実装例


 これらをすぐに使いこなせる必要はありませんが、覚えておいた方がよいです。
理由としては、ネットの記事などでは、実に色々な方法で処理が掲載されていますので、
読み手としては、いずれの方法も読み解ける必要があるためです。

 特にプログラムは、繰り返し使いたい処理はメソッドにまとめるメソッドは引数を利用することで内部処理が自動分岐化できる、という部分が重要になります。

 そういった部分を意識し、着目して処理を書いていくように心がけることで、処理が読み解けるようになり、
色々な書き方を覚えてスキルアップしていくことができます。



 今回は、基礎である配列や enum の機能を利用し、それを組み合わせたり、キャストして利用することで応用しています。
そのため、色々な構文をイメージして作っていくためには、基礎部分もしっかりと理解しておくことが大切になってきます。
ここであれば、引数の可読性を上げるために、enum を用意し、それをキャスト機能を利用して int 型の情報に置き換えることで
配列の index として利用できるロジックを組み込んでいます。


<enum を利用しない場合>
 modeChange.UpdateShowInfos(0);


<enum を利用する場合>
 modeChange.UpdateShowInfos((int)PrepareType.Remove);

 メソッド内で処理が配列によって分岐されて適用されるケースの場合、どちらの処理の方が読みやすいか、わかりやすいかという部分です。


メソッドの定義




メソッドの呼び出し命令



 実行命令は先ほども書いたように enum を用意した場合も含めて、2種類の方法が利用できます。

<enum を利用しない場合>
 modeChange.UpdateShowInfos(0);


<enum を利用する場合>
 modeChange.UpdateShowInfos((int)PrepareType.Remove);



考え方のポイント


 プログラムの難しい部分は、ルール化と定型(パターン)化が、異なっている部分です。

 例えば変数の宣言にはルールがあり、修飾子・データ型名・変数名 という順番で記述するように定義されています。
ですが、変数名にはルールはありません。
基本的にはキャメル式という方式が用いられていて小文字スタートで記述していますが、
これはルールでないので、大文字で書く人もいますし、_ を利用したキャメル式も記述出来ます。
そして名前も明確なもの(固定名)がありません。エンジニアが、どういった意図で使うのかを考えて、任意に命名します。

 このように、ルール化はされていても、名前にはルールがなく、そしてそれもパターンがない(用途によって異なる)ため、
テンプレートのようなものが作りにくく、数学のように1つの決まった回答というものが用意されていません。

 そのため、ルールの部分は暗記して覚えていくことができますが、それ以外の部分は暗記出来ません。
この辺りのイメージをしっかりと持っておくと、学習の際に役立つと思います。

 プログラムにおいて、ルールとパターンとは違う、そしてパターンは無い等しい、という考え方です。


メソッドの作り変え方


 そのような目線で、先ほどの ModeChange クラスに新しく用意した UpdateShowInfos メソッドを見てみます。

public void UpdateShowInfos(int index) {

    // 配列の場合
    txtPreparateModeChangeButton.text = infoDatas[index].message;
    btnPreparateModeChange.image.color = infoDatas[index].imageColor;

    // List の場合
    txtPreparateModeChangeButton.text = infoDataList[index].message;
    btnPreparateModeChange.image.color = infoDataList[index].imageColor;
}

 実行命令は先ほども書いたように enum を用意した場合も含めて、2種類の方法が利用できます。

<enum を利用しない場合>
 modeChange.UpdateShowInfos(0);


<enum を利用する場合>
 modeChange.UpdateShowInfos((int)PrepareType.Remove);

 実行命令で指定している引数は、UpdateShowInfos メソッドの引数に int 型が定義されているので、その型に合わせています。
では、UpdateShowInfos メソッドの引数が、int 型ではなく、enum の PrepareType 型である場合には、どうなるでしょうか。

 まず、UpdateShowInfos メソッド自体を作り変えてみます。

public void UpdateShowInfos(PrepareType prepareType) {

    // 配列の場合
    txtPreparateModeChangeButton.text = infoDatas[(int)prepareType].message;
    btnPreparateModeChange.image.color = infoDatas[(int)prepareType].imageColor;

    // List の場合
    txtPreparateModeChangeButton.text = infoDataList[(int)prepareType].message;
    btnPreparateModeChange.image.color = infoDataList[(int)prepareType].imageColor;
}

 引数が PrepareType に変わることで、そのままの情報を配列や List の番号に指定できなくなります。
配列と List の [ ] の部分は index の指定の場所であり、ルールとして int 型の情報が必要になるので、
このメソッド内で enum の PrepareType 型をキャストして、int 型に置き換えてから、利用するように変化しています。

 そうなると、実行命令の方にも変化があります。

まず、enum での指定しかできなくなりますので、必然的に命令は1種類になります。

 modeChange.UpdateShowInfos(PrepareType.Remove);

 先ほどはこの実行命令のタイミングで、UpdateShowInfos メソッドの引数の型に合わせるためにキャストして渡していましたが、
今回は、PrepareType が引数の型になっているので、このタイミングではキャストしないで処理を書けます。

 このように、メソッド1つとっても、引数の型の指定の方法で、異なる処理のロジックを考えるようになります。

 どちらがよりよいのかは書き手と読み手に委ねられますが、個人的には、この書き方の方が実行命令が分かりやすくなると思います。
ただし、UpdateShowInfos メソッド内でキャストするので、配列の [ ] でキャストする処理が見慣れない場合には、処理が読めない可能性もあります。
一長一短です。

モアベターな処理をつくることを心がけることが大切ですが、読み手によっては読めない可能性も出てくるケースもあるため、
平坦な処理を書いておいた方が無難になることもあります。

 大切なことは、このように、メソッドの引数の作り方にも色々な方法があるので、1つの固定パターンで考えるのではなく
どういう処理を作っていけば読みやすいか、書きやすいか、という部分にフォーカスした方がよい、という部分と
プログラムは書き手によって異なる書き方が出来、それがプログラムの柔軟性になっているので、
読みやすく汎用性の高い処理を作るためには、自分も色々な処理の書き方を学び(ルールを覚え)、
その中でどれがよいのか柔軟に方法に考えていく(ルールに基づいた自由度の中で模索する)、という部分とになります。



 この辺りの説明も読むだけですと難しかったりしますので、ノートなどに書いて、自分なりにまとめてみると、段々と理解が深まります。

 以上になります。

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Menu



プログラムの基礎学習

コード練習

技術/知識(実装例)

2Dおはじきゲーム(発展編)

2D強制横スクロールアクション(発展編)

3Dダイビングアクション(発展編)

2Dタップシューティング(拡張編)

レースゲーム(抜粋)

2D放置ゲーム(発展編)

3D脱出ゲーム(抜粋)

2Dリアルタイムストラテジー

2Dトップビューアドベンチャー(宴アセット使用)

3Dタップアクション(NavMeshAgent 使用)

2Dトップビューアクション(カエルの為に〜、ボコスカウォーズ風)

3Dトップビューアクション(白猫風)

VideoPlayer イベント連動の実装例

VideoPlayer リスト内からムービー再生の実装例(発展)

AR 画像付きオブジェクト生成の実装例

AR リスト内から生成の実装例(発展)

private



このサイト内の作品はユニティちゃんライセンス条項の元に提供されています。

管理人/副管理人のみ編集できます