【Unity】outパラメーター修飾子とは?メソッドから変数に値を返すための役割

outパラメーター修飾子とは? 未分類

こんにちは、ともくんのゲーム作り部屋にようこそ!

このページでは、

「outパラメーター修飾子ってなに?」

「Raycastにでてくるoutってなに?」

というお悩みの方に向けた内容となっています。

Unityで使われるC#などのプログラミング言語には、outパラメーター修飾子というものがあります。

このoutパラメーター修飾子とは、メソッドに引数でデータを渡す際に参照渡しをするための修飾子で、メソッド内での処理結果を引数に指定した変数に返すために使います。

例えば、UnityではRaycastメソッドなどを使う際に、引数で指定した変数に衝突したオブジェクト情報が返るように、outパラメーター修飾子が使われています。

そこでこのページでは、UnityのRaycastメソッドなどでも使われているoutパラメーター修飾子について、どういうものなのか、参照渡しの仕組みや使い方などをまとめていきます。

この記事を書いた人

ゲーム作りを学び始めた一児のパパです。
このブログは、子供から「ゲームを作ってみたい!」と言われ、非プログラマーでゲーム作りをしたことない僕が、ゲーム作りの本を読んで独学でゲーム開発を学んでいるブログです。
同じように初めてゲーム作りをしている方と一緒に学んでいけるようなブログに出来たらいいなと思っています。
また、「このコードはおかしい」とか「もっと良い書き方があるよ!」などあれば、どんどん指摘して頂けると助かります。

outパラメーター修飾子とは?

まずは、outパラメーター修飾子がどういうものなのかを紹介していきます。

参照渡しをするための修飾子のひとつ

outパラメーター修飾子とは、メソッドに引数を渡すときに参照渡しするためのパラメーター修飾子のひとつです。

メソッドに引数を渡す際の手法として、「値渡し」「参照渡し」というものがあります。

ここでは、この「値渡し」「参照渡し」の違いについて説明していきます。

値渡し

「値渡し」とは、メソッドを呼び出す際に、引数に指定した変数の値をコピーして引き渡す方法で、メソッド内でその値に対して変更する処理を加えても、変数の中身自体は変わることがありません。

例えば、以下のスクリプト内でint型の変数として「a」「b」を作っておき、「a」には「10」の値を代入、「b」には引数に指定した「a」を2倍にして返す「Double」というメソッドの値を入れるようにします。

using UnityEngine;

public class Test : MonoBehaviour
{
    void Start()
    {
        int a = 10;
        int b = Double(a);

        Debug.Log("変数aの値は「" + a + "」");
        Debug.Log("変数bの値は「" + b + "」");
    }

    int Double(int num)
    {
        num *= 2;
        return num;
    }
}

そして、10・11行目でaとbのそれぞれの値をコンソールウィンドウに表示させてみます。

すると、aには「10」、bには「20」が表示されており、aの中身が変わっていないのが分かります。

これは、引数で指定したaの値はコピーされた上で使われているので、変数aの中身自体は変わっていないことになります。

このように、引数に指定した値をコピーして渡す方法値渡しと言い、修飾子を付けない場合はこの値渡しになります。

参照渡し

参照渡しとは、引数に設定した変数が保存されている場所をメソッドに引き渡す方法で、メソッド内でその受け取った値に対して変更する処理を加えると、元の変数の中身自体も変わることになります。

この参照渡しをする場合は、引数の前に「ref」「in」「out」というパラメーター修飾子を付け、またメソッド内で受け取る変数にも、同じくそれぞれのパラメーター修飾子を付ける必要があります。

例えば、先ほどの値渡しで説明したスクリプトと同じものを準備して、Doubleメソッドの引数の変数と、Doubleメソッド内で受け取る変数numに、「ref」というパラメーター修飾子をそれぞれ付けておきます。

using UnityEngine;

public class Test : MonoBehaviour
{
    void Start()
    {
        int a = 10;
        int b = Double(ref a);  // 参照渡しするrefを付ける

        Debug.Log("変数aの値は「" + a + "」");
        Debug.Log("変数bの値は「" + b + "」");
    }

    int Double(ref int num) // 受け取る変数にrefを付ける
    {
        num *= 2;   // 変数aの値も書き変わる
        return num;
    }
}

そして、同じようにaとbのそれぞれの値をコンソールウィンドウに表示させてみます。

すると、aもbも「20」が表示されており、aの中身が変わっているのが分かります。

これは、引数で指定したaという変数の中身ではなく、その変数の保存場所をメソッドに引き渡しているため、Doubleメソッド内で受け取った変数のnumを書き換える(16行目)と、元の変数であるaの中身も書き変わることになります。

このように、引数に指定した変数の保存場所を引き渡す方法参照渡しと言い、「ref」「in」「out」という3つのパラメーター修飾子を付けた場合に参照渡しが行われます。

引数の変数にメソッドから値を返すのに使う

outパラメーター修飾子は、参照渡しする修飾子の中でも、引数に指定した変数を使ってメソッドから値を返すためだけに使う修飾子となっています。

参照渡しするパラメーター修飾子には、「ref」「in」「out」という3つの修飾子がありましたが、それぞれ役割が違います。

下記は、それぞれのパラメーター修飾子の役割をまとめたものになります。

参照渡しする修飾子メソッドに値を渡す役割
(入力)
メソッドから値を受け取る役割
(出力)
「ref」
「in」×
「out」×

この中で「out」は、メソッドから値を受け取る(書き換える)だけのパラメーター修飾子で、メソッド側に値を引き渡すという役割はありません。

例えば、以下のスクリプト内でint型の変数として「a」「b」を作っておき、「a」には「10」の値を代入、また「Square」というメソッド内で引数として「a」「b」を引き渡し、メソッド内で受け取った「num1」の値を二乗したものを「num2」に代入するという処理を行っています。

using UnityEngine;

public class Test : MonoBehaviour
{
    void Start()
    {
        int a = 10;
        int b;
        Square(a, out b);   // out修飾子を付けておく

        Debug.Log("変数aの値は「" + a + "」");
        Debug.Log("変数bの値は「" + b + "」");
    }

    void Square(int num1, out int num2) // out修飾子を付けておく
    {
        num2 = num1 * num1; // 計算結果をbの変数で受け取れる
    }
}

9行目で、bの引き渡しにだけoutパラメーター修飾子を付けておくことで、num2にはbが保存されている場所が共有されていることになります。

これで実際に実行してみると、

bにはaの二乗の「100」の値が表示されており、bの変数でメソッド内で処理された計算結果を受け取れていることが分かります。

このようにoutパラメーター修飾子は、メソッドで指定した引数の変数を使って、メソッド内の処理結果を受け取る役割だけを行う修飾子です。

outパラメーター修飾子の使い方

ここからは、outパラメーター修飾子の使い方について紹介していきます。

outを付けた変数は事前に初期化する必要がない

outパラメーター修飾子は、メソッドに値を渡す役割がないことから、引数でoutを付けた変数を事前に初期化する必要がありません。

通常、変数を作った場合、中身は空っぽのため、数値や文字列などのデータを入れて使うことになります。

using UnityEngine;

public class Test : MonoBehaviour
{
    void Start()
    {
        int a = 10; // 変数に値を入れて初期化する

        Debug.Log("変数aの値は「" + a + "」");
    }
}

しかし、outパラメーター修飾子を付けた変数の場合は、中身が入っていても入っていなくても使用することができるので、事前に変数を初期化しておく必要はありません。

using UnityEngine;

public class Test : MonoBehaviour
{
    void Start()
    {
        int a; // 変数に値を入れていない
        One(out a);

        Debug.Log("変数aの値は「" + a + "」");
    }

    void One(out int num)
    {
        num = 1;
    }
}

ちなみに、事前に初期化していても、そもそもメソッド側で値を受け取る役割が無いため、以下のようにメソッド内の計算の中で変数の値を使おうとすると、エラーが発生することになります。

using UnityEngine;

public class Test : MonoBehaviour
{
    void Start()
    {
        int a = 10; // 変数に値を入れて初期化する
        PlusOne(out a);

        Debug.Log("変数aの値は「" + a + "」");
    }

    void PlusOne(out int num)
    {
        num += 1;   // numには値が入っていないのでコンパイルエラーが発生
    }
}

なお、初期化について分からない方は、以下の記事で詳しく解説していますので、参考にしてみてください。

メソッド内では必ず初期化する必要がある

outパラメーター修飾子は、メソッド内での処理結果を受け取る役割があることから、メソッド内ではoutを付けた変数を必ず初期化する必要があります。

もう少し分かりやすく言うと、メソッドの処理の中で、outパラメーター修飾子で参照渡しした変数に値を必ず入れる必要があります。

例えば、引数の変数aにoutパラメーター修飾子を付けてメソッドに引き渡した際に、メソッド内で受け取った変数numに値を入れないとコンパイルエラーが発生します。

using UnityEngine;

public class Test : MonoBehaviour
{
    void Start()
    {
        int a;
        int b = SameNumber(out a);

        Debug.Log("変数aの値は「" + a + "」");
        Debug.Log("変数aの値は「" + b + "」");
    }

    int SameNumber(out int num)
    {
        return num; // numに値を入れていないのでコンパイルエラーが発生
    }
}

そのため、outパラメーター修飾子を付けた場合は、必ずメソッド内で変数に値を入れるようにしましょう。

using UnityEngine;

public class Test : MonoBehaviour
{
    void Start()
    {
        int a;
        int b = SameNumber(out a);

        Debug.Log("変数aの値は「" + a + "」");
        Debug.Log("変数aの値は「" + b + "」");
    }

    int SameNumber(out int num)
    {
        num = 5;    // 受け取った変数は必ず初期化する必要がある
        return num;
    }
}

UnityではRaycastメソッドで使われる

ここまでoutパラメーター修飾子の使い方をまとめていきましたが、Unityでのゲーム製作ではRaycastメソッドで、このoutパラメーター修飾子がよく使われています。

Raycastメソッドとは、シーン内でまっすぐに進む光線(Ray)を飛ばして、コライダーの付いているオブジェクトとの当たり判定を検知するメソッドです。

このRaycastメソッドは、以下のように記述することで、光線を飛ばして当たり判定があるかどうかをbool型で返してくれます。

Physics.Raycast(Ray ray, RaycastHit hitInfo)
  • ray:光線を飛ばす位置と方向
  • hitInfo:当たり判定のあるオブジェクト情報

この中で、光線で当たったオブジェクトの情報を取得するRaycastHit型の変数(hitInfo)を指定する際に、outパラメーター修飾子を使います。

実際に、キューブ型のオブジェクト(Cube)と球体型のオブジェクト(Sphere)をシーン内に配置して、Raycastメソッドを使ってマウスでクリックすると、オブジェクトの名前が表示される処理を作ってみます。

空のオブジェクトを作成して、以下のスクリプトを紐づけておきます。

using UnityEngine;

public class Test : MonoBehaviour
{
    void Update()
    {
        // マウスをクリックした場合
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);    // カメラからマウスカーソルへ向かう光線
            RaycastHit hit; // 当たり判定のあるオブジェクト情報(初期化していない)
            if (Physics.Raycast(ray, out hit))  // out修飾子を付けて引き渡す
            {
                Debug.Log(hit.collider.gameObject.name);    // hitでオブジェクト情報を受け取っている
            }
        }
    }
}

11行目の部分で、RaycastHit型の変数hitを宣言していますが、中身は何も入れていません。

そして、Raycastメソッドを呼び出す際に、引数で変数hitにoutパラメーター修飾子を付けて渡しています。

これにより、Raycastメソッドの中で変数hitからの値は受け取らずに、メソッド内で取得したコライダーの情報を変数hitに返すという処理が行われます。

この変数hitで受け取った情報から、14行目のようにオブジェクト名を取得することができるので、

マウスでクリックしたオブジェクトの名前をコンソールウィンドウに表示させることができています。

なお、Raycastメソッドについては、以下のページでも詳しく解説していますので、参考にしてみてください。

まとめ

このページでは、UnityのC#で使われるoutパラメーター修飾子について、どういうものなのか、役割や使い方までをまとめていきましたが、いかがでしたでしょうか?

outパラメーター修飾子とは、メソッドの引数で変数を渡す際に参照渡しするための修飾子のひとつで、メソッド内から処理結果を変数に返す役割を持つ修飾子です。

outパラメーター修飾子を付けると、メソッドにその変数の値を渡す役割は無く、メソッド内から値を受け取るだけの役割を持つことになります。

Unityでは、光線を使って当たり判定を取得するRaycastメソッドで、コライダーの情報を取得するRaycastHit型の変数を指定する際に、outパラメーター修飾子が使われます。

最後までお読みいただきまして、ありがとうございました!

コメント