LoginSignup
3

More than 5 years have passed since last update.

コルーチンでfor文のiを使用してオブジェクトを動的に位置設定したい件

Posted at

どういうこと?

例えばギャラリー画面で、N×Mのレイアウトでゲームオブジェクトの生成→配置を行いたい場合、同期処理じゃイけてないから、コルーチンで処理したい。
わけあって、以下のような処理のイメージ。

イメージ
private void Start{ StartCoroutine(Initialize()); }
private IEnumerator Initialize() {
    for (int j = 0; j < 2; j++) {
        for (int i = 0; i < 3; i++) {
            hoge.registInstantiate((obj) => {
                GameObject go = obj as GameObject;
                go.transform.localPosition = new Vector3(i*10f-300f, 100-j*140f, 0f);
                ...
            });
        }
    }
    yield return 0;
    hoge.StartInstantiate();    //registInstantiateで登録したアクションを一気に動かす
}

ただこれだと、実際にアクションを動かすタイミングだとiとかjが最後に更新された値(i=3, j=2)として処理されてしまう……困った。

対応策

  • iを一時変数に代入し、その値を使用する
  • メソッドをかませる

具体的に

前提:Unity5.4.0p3

ケース1:iを一時変数に代入し、その値を使用する

テストコード
private void Start{ StartCoroutine(testFor()); }
private IEnumerator testFor() {
    System.Action[] actions = new System.Action[6];
    for (int j = 0; j < 2; j++) {
        for (int i = 0; i < 3; i++) {
            int tmp_i = i;

            actions[j*3 + i] = () =>
            {
                Debug.Log("i = " + i + ", tmp_i = " + tmp_i);
            };
        }
    }
    yield return 0;

    for(int k=0; k<actions.Length; k++) { actions[k](); }
    yield break;
}
結果[NG]
i = 3, tmp_i = 2
i = 3, tmp_i = 2
i = 3, tmp_i = 2
i = 3, tmp_i = 2
i = 3, tmp_i = 2
i = 3, tmp_i = 2

ケース2:iを一時変数に代入し、その値を使用する+メソッドをかませる

テストコード
private void Start{ StartCoroutine(testFor()); }
private IEnumerator testFor() {
    System.Action[] actions = new System.Action[6];
    for (int j = 0; j < 2; j++) {
        for (int i = 0; i < 3; i++) {
            int tmp_i = i;

            actions[j*3 + i] = log(i, tmp_i);
        }
    }
    yield return 0;

    for(int k=0; k<actions.Length; k++) { actions[k](); }
    yield break;
}
private System.Action log(int i, int tmp_i) {
    System.Action action = () =>
    {
        Debug.Log("i = " + i + ", tmp_i = " + tmp_i);
    };
    return action;
}
結果[OK]
i = 0, tmp_i = 0
i = 1, tmp_i = 1
i = 2, tmp_i = 2
i = 0, tmp_i = 0
i = 1, tmp_i = 1
i = 2, tmp_i = 2

ただ、参考記事にあるように、Unity5.5系からだとケース1で解決できることを確認済。

ケース1をUnity5.5.2p4で動かした結果[OK]
i = 3, tmp_i = 0
i = 3, tmp_i = 1
i = 3, tmp_i = 2
i = 3, tmp_i = 0
i = 3, tmp_i = 1
i = 3, tmp_i = 2

参考にさせていただきました記事

-以上-

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3