Unityに関連する記事です

データ型の種類


 C# プログラミング言語には、値型参照型の 2 種類のデータ型があります。
こちらの記事も参考にしてください。
=> データ型 ー値型と参照型ー

参考サイト
MicroSoft
値型
MicroSoft
参照型


初期値


 C#では、変数を宣言すると、それぞれの型に応じたデフォルトの値が自動的に設定されます。
これを初期値(しょきち)と呼びます。

 初期値を正しく理解しておくと、変数を宣言した時点でどのような状態になるかを予測しやすくなります。



 値型の初期値は、その型に応じて定まっています。 例えば、intやfloatの初期値は0、boolの初期値はfalseとなります。

 一方、参照型の初期値はnull(ヌル)です。 これは、何も参照していない状態を表します。



 それでは以下に、それぞれの型による初期値の例を示します。
 
using UnityEngine;

public class PointClass
{
    public int Point;
}

public class DefaultValuesExample : MonoBehaviour
{
    // 値型
    int a;  // 初期値は 0
    float b;  // 初期値は 0.0
    bool c;  // 初期値は false

    // 参照型
    PointClass p;  // 初期値は null
    string s;  // 初期値は null

    void Start()
    {
        Debug.Log(a);  // Console ビューに 0 と出力
        Debug.Log(b);  // Console ビューに 0 と出力
        Debug.Log(c);  // Console ビューに false と出力

        Debug.Log(p);  // Console ビューに null と出力
        Debug.Log(s);  // Console ビューに null と出力
    }
}


<初期値の活用方法>


 初期値が設定されているとはいえ、それがそのままプログラムに適しているかは状況によります。
より具体的な値を必要とする場合、適切な値で初期化することが重要です。

 例えば、プレイヤーの HP の値を int 型で表す場合、int 型の初期値の 0 では負けたことになってしまいます。
こういったときには int 型の初期値 0 ではなく、100 とか 500 といった、適切な値を代入して初期化して利用する、といった形で
初期値の活用方法を考えていくことが大切です。


null チェック


 参照型の変数がnullの初期値を持つことにより、その変数がまだ有効なオブジェクトを参照していないことがわかります。
そのため、nullである参照型変数に対する操作を行う前には、適切なオブジェクトで初期化(あるいは取得)すること、
必ずnullでないことを確認する(その変数が有効なオブジェクトを指していることを確認する)ことが重要です。

 この確認方法を「null チェック」と呼びます。

 サンプルコードで null チェックの使い方を2パターン紹介します。


<null チェックのサンプルコード 


 一般的な null チェックの方法です。
GetComponent メソッドを利用して取得した参照が null ではないかを確認しています。

using UnityEngine;

public class NullCheckExample_1 : MonoBehaviour
{
    Rigidbody rb = null;

    void Start() 
    {
        // 適切なオブジェクトを取得する
        rb = GetComponent<Rigidbody>();
        
        // rbがnullでないことを確認してから操作を行う(null チェック)
        if (rb != null)
        {
            rb.mass = 10;
        }
    }
}

 より丁寧に記述する場合には、else 節も用意し、Debug.Log メソッドを記述してエラーログを出力します。

using UnityEngine;

public class NullCheckExample_1 : MonoBehaviour
{
    Rigidbody rb = null;

    void Start() 
    {
        // 適切なオブジェクトを取得する
        rb = GetComponent<Rigidbody>();
        
        // rbがnullでないことを確認してから操作を行う(null チェック)
        if (rb != null)
        {
            rb.mass = 10;
        }
        else 
        {
            Debug.Log("rb 変数が null です");
        }
    }
}

 このようにして null チェックを行うことで、エラーの原因をすぐに特定することができ、またエラーによってゲームが停止することを未然に防ぐことが出来ます。


<null チェックのサンプルコード◆


 こちらの方法では TryGetComponent メソッドを利用して、rb 変数へのインスタンスの取得と、null チェックの両方を一緒に行っています。

using UnityEngine;

public class NullCheckExample_2 : MonoBehaviour
{
    Rigidbody rb = null;

    void Start() 
    {
        // 適切なオブジェクトを取得し、rbがnullでないことを確認してから操作を行う(null チェック)
        if (TryGetComponent(out rb))
        {
            rb.mass = 10;
        }
    }
}

 こちらも else 節を用意できます。

using UnityEngine;

public class NullCheckExample_2 : MonoBehaviour
{
    Rigidbody rb = null;

    void Start() 
    {
        // 適切なオブジェクトを取得し、rbがnullでないことを確認してから操作を行う(null チェック)
        if (TryGetComponent(out rb))
        {
            rb.mass = 10;
        }
        else 
        {
            Debug.Log("rb 変数が null です");
        }
    }
}


<ケーススタディ ー処理の書き換え方ー>


 if 文を利用した多くのケースの場合、〜 であったら、という形で
true の際に処理を分岐させる書式で書いていくケースがあります。

 ただし、プログラムには書式は1つではありません。
特に if 文の場合、複数の分岐が絡んでくることもあるため、if 文の中に別の if 文といった書式もあります。

 この場合、if 文が増える程、ネスト(入れ子構造)が深くなってしまって処理が読みにくくなります。

 こういったケースの場合、適切なタイミングで return キーワードを活用して処理を止めてしまう手法があります。

 先ほどの null チェックの場合で、処理を置き換えてみましょう。



using UnityEngine;

public class NullCheckExample_3 : MonoBehaviour
{
    Rigidbody rb = null;

    void Start() 
    {
        // 適切なオブジェクトを取得し、rbがnullでないことを確認してから操作を行う(null チェック)
        if (!TryGetComponent(out rb))
        {
            Debug.Log("rb 変数が null です");
            return;
        }
        rb.mass = 10;
    }
}

 if 文の条件式を 〜 ではなかったら、という形で逆説的に用意することで、if 文に該当したら処理が停止するという書式が記述できます。
そのため、rb 変数に対しての処理は if 文の外側に記述できるようになりました。また、else 節も省略することができ、すっきりしました。

 今回の例では if 文は1つだけでしたが、それだけでも読みやすさが異なります。
特にネストが深い if 文の場合、この return を活用した処理の記述が効果的です。

 プログラムには色々な書き分け方ができることを念頭に置いておくことで、より視野の広い処理を記述できるようになります。


<NullReferenceExceptionエラー>


 以上のことからもわかるように、Unity でも頻繁に目にする機会のある NullReferenceExceptionエラーは、
nullの状態を持つことが可能な参照型に特有のエラーです。
値型の変数はnullを保持することができません(例外もありますが、基本的には保持できません)ので、このエラーを引き起こすことはありません

using UnityEngine;

public class NullReferenceExceptionExample : MonoBehaviour
{
    Rigidbody rb;   // 参照型の初期値は null です

    void Start() 
    {
        // この時点では rb はnullなので、次の行は実行時エラーを引き起こします
        rb.mass = 10;  // Error: NullReferenceException
    }
}

 この例では、rb 変数への代入処理がないため、rb 変数を利用した行で NullReferenceExceptionエラーが発生します。
先程の null チェックもないため、エラーを未然に防ぐことも出来ません



 データ型の違いを理解することで、エラーメッセージが示す問題を特定するために役立ちます。

 なぜなら、NullReferenceExceptionエラーが発生した場合、問題となっているのは参照型の変数またはオブジェクトであり、
それがnullであることが原因である可能性が高いと推測することができます。よって、値型の変数については確認しなくても問題がないことも合わせて分かります。

 Null に起因するエラーの場合、エラーの本質を理解しておくことで原因の切り分けを行うことが出来、
問題の解決に向けてのデバッグ作業が効率的に進めることが出来ます。


まとめ


 値型と参照型はそれぞれ異なる振る舞いをしますので、使い分けが重要です。

 値型はその値そのものをコピーするため、元の変数と新たに作成した変数は独立した存在となります。
一方、参照型はメモリ上のオブジェクトへの参照をコピーするため、同一のオブジェクトに対する変更がすべての参照から見えます。

 参照型を使用する際には、nullという特殊な状態を理解し、NullReferenceExceptionが発生しないように注意することが重要です。
値型ではこのようなエラーは発生しませんが、それは値型が常に有効な状態(値を保持している状態)であるからです。

 プログラミングを進める上で、これらの違いを意識して変数を扱うことが求められます。
値型と参照型の違いを理解し、それぞれが最も適している状況で使用することが、良いコードを書くための基本となります。

コメントをかく


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

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

Menu



技術/知識(実装例)

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

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

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

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

レースゲーム(抜粋)

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

3Dレールガンシューティング(応用編)

3D脱出ゲーム(抜粋)

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

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

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

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

VideoPlayer イベント連動の実装例

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

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

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

private



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

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