Tsuの雑記¯\_(ツ)_/¯

主に製作メモ・備忘録として使用。製作したアプリのリンクもあります。

【Unity】呼び出す関数を三項演算子で分岐させる【C#】

代入する値の分岐は,三項演算子(条件演算子)でif文より簡潔に記述できます。

また三項演算子は,実行するメソッドも分岐させる事が出来ます。

そのためには,デリゲートを使用する必要があります。

それでは,いくつか実例を挙げて御説明いたします。

(2019/11/11)追記しました。

(Unity 2018.3.0f2)

三項演算子とは

docs.microsoft.com

条件式を評価してtruefalseに応じた結果が実行されるため,if-else文と似ています。

(厳密には,単純に代用すべきでないそうですが……。)

三項演算子の使用例を,以下に示します。

using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    // 整数値は “50”
    [SerializeField, Range(0, 100)] int number = 50;

    void Update()
    {
        // 1ずつ加算して 100 に達したら0にする
        number = (number < 100) ? (number + 1) : 0;

        // 同じ処理を if 文で
        /*if (number < 100)
        {
            number = number + 1;
        }
        else
        {
            number = 0;
        }*/
    }
}

上記のようなスクリプトファイルを適当な GameObject にアタッチして,Play してみましょう。

UnityEditor の Inspector ウィンドウで number の値が増えている画像
number の値が増えていく

numberの値が増えてゆき,100に達すると0になるのが分かると思います。

?の左辺を評価して真trueであれば?の右辺を実行し,偽falseであれば:の右辺が実行されます。

コメントアウトした部分のif文に比べ,分岐を1行で簡潔に記述できていますね。

今回は値の増減を視覚的に分かりやすくするため,numberに RangeAttribute を付与して Inspector 上にスライダーを表示しています。

docs.unity3d.com

デリゲートとは

デリゲートを簡単に説明すると,関数を格納できる変数のような物です。

unity3d.com

以下,デリゲートを使用したメソッド呼び出しの例です。

using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    // デリゲートの宣言
    delegate void Method();

    void Start()
    {
        // MethodA を代入
        Method method = MethodA;

        // 代わりに Action を使えばデリゲートの宣言も省略できる
        //System.Action method = MethodA;
        
        // デリゲート実行
        method();

        // MethodB を代入
        method = MethodB;
        // MethodA を追加
        method += MethodA;
        // MethodA を削除
        method -= MethodA;

        // デリゲート実行
        method();
    }

    void MethodA()
    {
        // コンソールに “A” と表示
        Debug.Log("A");
    }

    void MethodB()
    {
        // コンソールに “B” と表示
        Debug.Log("B");
    }
}

2度繰り返されるmethod()の実行前にそれぞれ別のメソッドを代入しているため,実際には2種類のメソッドが実行されています。

Console に“A”と“B”が1行ずつ表示されている画像
2種類のメソッドが呼び出されている

これを利用して,三項演算子の代入部分でメソッドを選ぶ事が出来ます。

ちなみにスクリプト内にも記述したように,Actionを使用すればデリゲートの宣言も省略できます。

docs.microsoft.com

三項演算子とデリゲート

それでは,実際にやってみましょう。

using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    // デリゲート
    delegate int Method();
    // 加算・減算
    enum Calculation { Addition, Subtraction };

    // 列挙型は “加算”
    [SerializeField] Calculation calculation = default;
    // 整数値は “50”
    [SerializeField, Range(0, 100)] int number = 50;

    void Update()
    {
        // 計算実行
        Calculate();
    }

    void Calculate()
    {
        // 加算・減算状態の切り替え
        calculation = (number <= 0) ? Calculation.Addition
            : (number >= 100) ? Calculation.Subtraction
            : calculation;

        // 呼び出すメソッドの切り替え
        var method = (calculation == Calculation.Addition) ? (Method)Add
            : Subtract;

        // 代わりに Func<TResult> を使えばデリゲートの宣言も省略できる
        //var method = (calculation == Calculation.Addition) ? (System.Func<int>)Add
        //    : Subtract;

        // 計算メソッド呼び出し
        method();
    }

    int Add()
    {
        // 1加算
        return number++;
    }

    int Subtract()
    {
        // 1減算
        return number--;
    }
}

これをアタッチした GameObject を Inspector 画面で見ると,次の画像のようになります。

UnityEditor の Inspector 上で number の値が増減している画像
Addition と Subtraction が交互に切り替わる

次の部分が,今回のポイントになっている三項演算子です。

// 呼び出すメソッドの切り替え
var method = (calculation == Calculation.Addition) ? (Method)Add
    : Subtract;

左辺には型推論varが使用できますが,呼び出すメソッド名のいずれか1つにはキャスト(Method)が必要になります。

docs.microsoft.com

ちなみにスクリプト内にも記述したように,Func<TResult>を使用すればデリゲートの宣言も省略できます。

docs.microsoft.com

三項演算子ラムダ式

(2019/11/11)以下の内容を追記しました。

ラムダ式を使用する事で,更に記述を簡略化できます。

docs.microsoft.com

using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    // デリゲート
    //delegate int Method();
    // 加算・減算
    enum Calculation { Addition, Subtraction };

    // 列挙型は “加算”
    [SerializeField] Calculation calculation = default;
    // 整数値は “50”
    [SerializeField, Range(0, 100)] int number = 50;

    void Update()
    {
        // 計算実行
        Calculate();
    }

    void Calculate()
    {
        // 加算・減算状態の切り替え
        calculation = (number <= 0) ? Calculation.Addition
            : (number >= 100) ? Calculation.Subtraction
            : calculation;

        // 呼び出すメソッドの切り替え
        //var method = (calculation == Calculation.Addition) ? (Method)Add
        //    : Subtract;

        // 代わりに Func<TResult> や Action を使えばデリゲートの宣言も省略できる
        //var method = (calculation == Calculation.Addition) ? (System.Func<int>)Add
        //    : Subtract;

        // 更にラムダ式を使えば Add() や Subtract() 等のメソッドも不要となる
        var method = (calculation == Calculation.Addition) ? (System.Func<int>)(() => (number = number + 1))
            : (() => (number = number - 1));

        // 計算メソッド呼び出し
        method();
    }

    /*int Add()
    {
        // 1加算
        return number++;
    }

    int Subtract()
    {
        // 1減算
        return number--;
    }*/
}

今回のAdd()Subtract()ように単純な処理であれば,ラムダ式で直接記述した方が良さそうですね。

以上,呼び出す関数を三項演算子で分岐させる方法でした。