Menu
CoddyTech

ラムダ式

CoddyのUnityジャーニー「本格的なゲームを作る」セクションの一部。レッスン 7/60。

AddListenerはパラメーターを取らないメソッドを受け取ります。クリック時に色を受け取るPaint(Color.red)を呼び出すには、その場でメソッドを書きます。() => Paint(Color.red)のようにします。これはラムダ、つまり名前のないメソッドです。()にはパラメーターを記述しますが、ここではありません。また、=>の後には本体が続きます。1つのステートメント、または複数の場合は{ }で囲んだブロックです。

public Button redButton;
public Button blueButton;
public Button resetButton;
public Renderer lamp;
private int changes;

void Start()
{
    redButton.onClick.AddListener(() => Paint(Color.red));
    blueButton.onClick.AddListener(() => Paint(Color.blue));
    resetButton.onClick.AddListener(() =>
    {
        changes = 0;
        lamp.material.color = Color.white;
    });
}

void Paint(Color color)
{
    lamp.material.color = color;
    changes++;
}

1つのPaintメソッドで両方の色ボタンに対応し、それぞれのラムダが個別の色を渡します。ラムダは使用する変数をキャプチャします。値をコピーするのではなく、実行時にその値を読み取ります。リセット用のラムダは、Start()が終了してからずっと後でも、クリックされるたびにフィールドchangesを設定します。

ループではこの点が問題になります。swatches[i].onClick.AddListener(() => Paint(colors[i]));では、すべてのラムダが同じiをキャプチャします。誰かがクリックする頃にはループが終わり、iはcolors.Lengthになっているため、すべてのスウォッチでIndexOutOfRangeExceptionが発生します。ループ内で宣言された変数は、ループが回るたびに新しく作られるので、iを別の変数にコピーして、そのコピーをキャプチャします。

for (int i = 0; i < swatches.Length; i++)
{
    int index = i;
    swatches[i].onClick.AddListener(() => Paint(colors[index]));
}
challenge icon

チャレンジ

簡単

Start()で金庫のキーパッドを接続します。

  1. forを使ってkeysをループ処理します。ループ内でint digit = i + 1;を宣言し、keys[i]を() => Press(digit)に接続します。
  2. clearButtonを、entered = ""を設定してShowCode()を呼び出す1つのラムダ式に接続します。

「プレイ」を押して3、1、2と入力すると、画面にOpenと表示されます。その後、「確認」を押します。

自分で試してみよう

using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class Keypad : MonoBehaviour
{
    public Button[] keys;
    public Button clearButton;
    public TMP_Text codeText;
    public GameObject door;
    public string secret = "312";
    private string entered = "";

    void Start()
    {
        ShowCode();
        // 各キーをそれぞれの数字を渡して Press に接続し、clearButton をコードの消去処理に接続する
    }

    void Press(int digit)
    {
        entered += digit;
        ShowCode();
        if (entered.Length == 3)
        {
            if (entered == secret)
            {
                door.SetActive(false);
                codeText.text = "Open";
            }
            else
            {
                codeText.text = "Wrong";
            }
            entered = "";
        }
    }

    void ShowCode()
    {
        codeText.text = "Code: " + entered;
    }
}

本格的なゲームを作るのすべてのレッスン

自分で練習してみよう: Unityプレイグラウンド