You are currently viewing Unity LINQ遅延評価でバグった

Unity LINQ遅延評価でバグった

以下のようなコードを作成し、「ランダムにターゲットを出現させる」コードを作りました

foreach (var target in selectedLandolts)
{
    // ターゲットの親オブジェクトを取得し、スポーン座標を設定する
    target.transform.parent.position = selectedSpawnPoints.ElementAt(index).transform.position;
    target.transform.parent.rotation = selectedSpawnPoints.ElementAt(index).transform.rotation;

    Debug.Log($"[StartMiniGame] Spawn {target.transform.parent.name} at {selectedSpawnPoints.ElementAt(index).name}");

    FsmUtils.FindFsmOnGameObject(target, "MoveControl").SendEvent(FSMEventConstants.POPUP_LANDOLT);
    index++;
}

上記コードについて、selectedLandoltsがターゲット、selectedSpawnPointsがターゲット発生元です
スポーンポイントは4か所設定されていて、うち2か所をランダムに選択する仕様でした

出現箇所が一致しない

動作させると、実際のスポーンポイントとターゲットのスポーン位置がずれる現象が発生
デバッグコードを挿入して確認するも原因がわからず、Claudeさんに聞いてみました

罠:LINQの遅延評価について

ランダムにスポーンポイントを取得するコードは以下の通りです

var selectedSpawnPoints = spawnPoints
.OrderBy(_ => Random.value)
.Take(spawnCount);

上記コードだと「ランダムに選択する準備を行った状態」であり、実際の取得はデータが利用されるとき(今回のケースではElementAtを呼び出したとき)になるとのこと

しかも、ElementAtを複数呼び出していたため、呼び出すごとに異なるオブジェクトが取り出されていたことがバグの原因でした

対策方法

toList()でデータを確定させる

以下のように記述することで、データが確定され、取り出されるデータも安定します

var selectedSpawnPoints = spawnPoints
.OrderBy(_ => Random.value)
.Take(spawnCount)
.ToList();

ElementAt()の呼び出しを1度だけにする

ElementAtを複数呼び出すことで毎回オブジェクトが変わってしまうので、一度だけ呼び出して、呼び出したオブジェクトをキャッシュしておくことでも対応できます

foreach (var target in selectedLandolts)
{
    // ターゲットの親オブジェクトを取得し、スポーン座標を設定する
    GameObject obj = selectedSpawnPoints.ElementAt(index);
    target.transform.parent.position = obj.transform.position;
    target.transform.parent.rotation = obj.transform.rotation;

    Debug.Log($"[StartMiniGame] Spawn {target.transform.parent.name} at {obj.name}");

    FsmUtils.FindFsmOnGameObject(target, "MoveControl").SendEvent(FSMEventConstants.POPUP_LANDOLT);
    index++;
}

以上

C#は独学とノリで利用していたので、LINQの遅延評価については初めて知った内容でした
とはいえ、何か困ったことがあればAIに相談するとおおむね原因が解決できるため、以前より困ることは少なくなった気がします

今後もC#やUnity特有の仕様で詰まることがありそうですが、落ち着いて対処していきたいですね

created by Rinker
¥4,180 (2026/7/17 12:05:39時点 楽天市場調べ-詳細)

コメントを残す