Unityに関連する記事です

if 文の利用方法による処理の作り変え方


 if 文による処理の条件式を作成する際、 屐舛覆蕕弌{ } 内の処理を行う」という書式で記述していく方法がありますが、
逆の観点から「〜ならば、{ } 内の処理を行わない」という書式によって記述も出来ます。

 そのため、常に両方の処理のイメージを作れるように心がけることが重要です。
特にネストが深くなりそうな場合には、△僚萢と return キーワードを組み合せる手法が処理を見やすく作っていくことが出来ます


<if 文を,亮衙,乃述したケース。ネストが深くなりやすい>
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Sample_if_0 : MonoBehaviour {

    private bool isAttack;
    private Rigidbody rb;


    private void Update() {

        // ,両豺隋↓,両魴錣鯔たした上で、次の条件を満たす、というケースでの記述が増えるため、ネストが深くなりやすい
        if (isAttack) {
            if (rb != null) {
                rb.AddForce(transform.forward * 10, ForceMode.Acceleration);
            }
        }
    }
}

  ↓

<if 文を△亮衙,乃述して return を利用したケース_その1。ネストを浅くできる>
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Sample_if_1 : MonoBehaviour {

    private bool isAttack;
    private Rigidbody rb;


    private void Update() {

        // ネストを浅くする方法は、「〜ならば〜する」という処理の「逆のパターンの if 文を考える」ことです
        // isAttack ならば、ではなく、isAttack でないなら、と考えることで return を活用し、ネストを浅くできます
        if (!isAttack) {
            return;
        }

        if (rb != null) {
            rb.AddForce(transform.forward * 10, ForceMode.Acceleration);
        }
    }
}


<if 文を△亮衙,乃述して return を利用したケース_その2。ネストを浅くした上で、処理を簡潔に記述できる>
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Sample_if_2 : MonoBehaviour {

    private bool isAttack;
    private Rigidbody rb;


    private void Update() {

        // if 文の条件内に return の対象となる変数を合わせて記述することで、さらに処理をすっきりと記述することが出来ます。
        if (!isAttack || rb == null) {
            return;
        }

    // この処理が実行されるタイミングは、上記の条件以外のときであることが保証されます。そのため、if 文で囲む必要がなくなります。
        rb.AddForce(transform.forward * 10, ForceMode.Acceleration);
    }
}


<if 文を△亮衙,乃述して return を利用したケース_その3。ネストを浅くした上で、処理を簡潔に記述できる>
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Sample_if_3 : MonoBehaviour {

    [SerializeField]
    private GameObject enemy;

    private void OnTriggerStay(Collider other)
    {
        if (enemy == null) {
            return;
        }

        if (other.gameObject == enemy)
        {
            Debug.Log("同じ enemy");    
        }
    }
}


 プログラムを考えて書けるようになってくると、どうしても同じパターンに当てはめて処理をつくりがちになります。
そうではなくて、様々な角度から処理の内容を検討するという視点を持つことで、処理を書き分けていくことが出来るようになり、
結果的に、読みやすい処理を構築する記述方法を覚えていくことが出来ます。

 if 文を利用して処理をつくっていく場面は多いので、一度書いてうまく動作した処理であっても、他に書き方はないのか? という疑問を持ち、
よりよい処理の書き方を探求する気持ちを忘れないようにすることが、ひいてはスキルアップにつながり、上達への近道になります。


タグを利用しない判定方法の処理の作り変え方


 一般的なタグを利用した処理の判定方法を記載します。

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

public class CollisionSample : MonoBehaviour {

    private EnemyController enemy;


    private void OnCollisionEnter(Collision col) {

        // まずタグで判定を行い
        if (col.gameObject.CompareTag("Enemy")) {

      // 続いてクラスの取得を行い、処理をつなげていく
            enemy = col.gameObject.GetComponent<EnemyController>();
            enemy.Damage();
        }
    }
}

 Tag の判定はなるべく止めます。理由は Tag の判定後に、そのゲームオブジェクトにアタッチされているクラスの取得を行うケースが多いので
それであれば最初から「クラスがアタッチされているか」を判定し、かつ、クラスの情報を利用できる状態にする TryGetComponent を利用した方がいいです。

 そうすれば処理を判定する if 文は1つでよいため、ネストも浅くでき、かつ、メンバ変数も不要になります。


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

public class CollisionSample_Refact : MonoBehaviour {

    private void OnCollisionEnter(Collision col) {

        // TryGetComponent メソッドを利用し、指定したクラスがアタッチされているゲームオブジェクトであるか判定した上で、必要なクラスを取得できる
        if (col.gameObject.TryGetComponent(out EnemyController enemy)) {

      // クラスの取得が済んでいるので、GetComponent メソッドが不要になり、処理をつなげていくことができる
            enemy.Damage();
        }
    }
}


ローカル関数の活用方法


 特定のメソッド内からしか実行命令のないメソッドは、通常のメソッドではなく、実行命令の書いてあるメソッド内に
ローカル関数として定義した方が処理を読み解きやすくなります。コルーチンメソッドもローカル関数が利用できます。

 ローカル関数は自動的に private 扱いになるため、アクセス修飾子は記述できません。


<ローカル関数を活用しないケース>
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NormalMethodSample : MonoBehaviour {

    public void SetUp() {
        StartCoroutine(DelayAttack());
    }

  private IEnumerator DelayAttack() {

        yield return new WaitForSecounds(1.0f);
        Debug.Log("Attack");
    }
}


<ローカル関数を活用するケース>
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LocalMethodSample_Refact : MonoBehaviour {

    public void SetUp() {
        StartCoroutine(DelayAttack());


        /// <summary>
        /// SetUp メソッド内でのみ使用するローカル関数
        /// 呼び出し元が1つのメソッドに限定されているメソッドは、そのメソッド内にローカル関数を用意した方が処理が読みやすくなります
        /// </summary>
        /// <returns></returns>
        IEnumerator DelayAttack() {  // 修飾子は削除

            yield return new WaitForSecounds(1.0f);
            Debug.Log("Attack");
        }
    }
}

 メソッド内であればローカル関数の宣言はどこでも可能です。
例えば下記のように記述してあっても問題ありません。


<ローカル関数の宣言 
    public void SetUp() {
        
        /// <summary>
        /// SetUp メソッド内でのみ使用するローカル関数
        /// 呼び出し元が1つのメソッドに限定されているメソッドは、そのメソッド内にローカル関数を用意した方が処理が読みやすくなります
        /// </summary>
        /// <returns></returns>
        IEnumerator DelayAttack() {  // 修飾子は削除

            yield return new WaitForSecounds(1.0f);
            Debug.Log("Attack");
        }

        StartCoroutine(DelayAttack());
    }



<ローカル関数の宣言◆
    public void SetUp() {
        StartCoroutine(DelayAttack());


        /// <summary>
        /// SetUp メソッド内でのみ使用するローカル関数
        /// 呼び出し元が1つのメソッドに限定されているメソッドは、そのメソッド内にローカル関数を用意した方が処理が読みやすくなります
        /// </summary>
        /// <returns></returns>
        IEnumerator DelayAttack() {  // 修飾子は削除

            yield return new WaitForSecounds(1.0f);
            Debug.Log("Attack");
        }

        // 処理の前後にローカル関数が宣言してあっても問題ありません。
    Debug.Log("End Attack");        
    }

 メソッド内に定義できるローカル関数の数にも制限はないため、複数のローカル関数を1つのメソッド内に定義することも出来ます。

 プログラムは、決められた規則の中であれば、エンジニアが自分で考えた独自の処理を記述することができます。
イメージした処理をまずは書いてみて、動作するかを確認してみるとよいでしょう。
勝手に出来ないものと思い込まずに、どうすればいいのか、という観点から考えていくようにすることが大切です。

 ロジックを考えていくことは大変ではありますが、これはプログラムを書いて処理を動かす醍醐味であり、他では得難い体験にも繋がります。
 


 以上になります。

コメントをかく


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

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

Menu



プログラムの基礎学習

コード練習

技術/知識(実装例)

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

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

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

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

レースゲーム(抜粋)

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

3D脱出ゲーム(抜粋)

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

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

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

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

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

VideoPlayer イベント連動の実装例

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

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

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

private



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

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