第9週:合体のバグを直して仕上げよう
前回、同じ番号の玉がぶつかったら合体するところまで作りました。 でも、合体後の玉が2個できてしまうバグが残っています。
原因も分かっています。玉AとBがぶつかると、Unityは
AとBの両方のOnCollisionEnter2Dを呼ぶため、
どちらも「自分が新しい玉を作らなければ」と動いてしまうからです。
今日はこのバグを直して、合体を完成させます。
- 2つのうち片方だけが合体処理をするようにする
- 3つ同時にぶつかったときのバグも防ぐ
- 完成版の
Ballスクリプトを読み解く
対策1:片方だけが担当する
Section titled “対策1:片方だけが担当する”「AとBのどちらが合体処理をするか」を決めるルールが必要です。
GetInstanceIDで決める
Section titled “GetInstanceIDで決める”Unityのオブジェクトは、それぞれ違うID番号を持っています。 これを比べれば、機械的に片方を選べます。
// 自分のIDが相手より小さいなら、相手にまかせて何もしないif (GetInstanceID() < other.GetInstanceID()) return;入れてみよう
Section titled “入れてみよう” // いちばん大きい玉は合体しない if (nextPrefab == null) return;
// 2つのうち片方だけが処理する if (GetInstanceID() < other.GetInstanceID()) return;
// 2つの真ん中の位置を計算 Vector3 center = (transform.position + other.transform.position) / 2f;再生して確認してください。 合体後の玉が1個だけになりました!
対策2:3つ同時のバグを防ぐ
Section titled “対策2:3つ同時のバグを防ぐ”まだ問題が残っています。 同じ番号の玉が3つ以上、同時にぶつかったときです。
「もう合体した」という印をつける
Section titled “「もう合体した」という印をつける”// すでに合体したかどうかを覚えておくprivate bool merged = false;一度合体したらtrueにして、
2回目以降は何もしないようにします。
完成版のBallスクリプト
Section titled “完成版のBallスクリプト”using UnityEngine;
public class Ball : MonoBehaviour{ // この玉の番号(1〜6) public int level = 1;
// 合体してできる玉(いちばん大きい玉はNone) public GameObject nextPrefab;
// すでに合体したか private bool merged = false;
void OnCollisionEnter2D(Collision2D collision) { // 相手のBallスクリプトを取り出す Ball other = collision.gameObject.GetComponent<Ball>();
// 1. 相手が玉でない(壁・床)なら何もしない if (other == null) return;
// 2. 番号が違うなら合体しない if (other.level != level) return;
// 3. どちらかが合体済みなら何もしない if (merged || other.merged) return;
// 4. いちばん大きい玉は合体しない if (nextPrefab == null) return;
// 5. 2つのうち片方だけが処理する if (GetInstanceID() < other.GetInstanceID()) return;
// ここまで来たら合体する
// 両方に「合体した」印をつける merged = true; other.merged = true;
// 2つの真ん中の位置を計算 Vector3 center = (transform.position + other.transform.position) / 2f;
// 1つ大きい玉を作る Instantiate(nextPrefab, center, Quaternion.identity);
// 元の2つを消す Destroy(other.gameObject); Destroy(gameObject); }}再生して確認
Section titled “再生して確認”- 同じ玉2つがぶつかると、1つ大きい玉に1個だけ変わる
- 番号が違う玉同士はぶつかるだけで合体しない
- 運がよければ連鎖が起きる(合体してできた玉がさらに合体)
- いちばん大きい紫の玉は、それ以上合体しない

5つのifの意味をおさえよう
Section titled “5つのifの意味をおさえよう”完成版にはifが5つ並んでいます。どれも必要です。
| 番号 | 条件 | 無いとどうなる |
|---|---|---|
| 1 | other == null |
壁にぶつかるたびにエラーが出る |
| 2 | other.level != level |
違う玉でも合体してしまう |
| 3 | `merged | |
| 4 | nextPrefab == null |
レベル6でエラーが出る |
| 5 | IDの比較 | 合体後の玉が2個できる |
よくある問題と解決方法
Section titled “よくある問題と解決方法”| 症状 | 原因と対処法 |
|---|---|
| まったく合体しない | メソッド名が OnCollisionEnter2Dか確認(2Dを忘れがち) |
| 合体しない(エラーも出ない) | PrefabにBallスクリプトを付け忘れている |
| 合体後の玉が2個できる | IDを比べるifが入っていない |
| 玉が3個以上あると増殖する | mergedのifが入っていない |
| 違う番号の玉が合体する | PrefabのLevelが全部1のまま。1〜6を設定する |
| 無限に合体し続ける | Ball6のNext PrefabにBall6などを入れている。空にする |
NullReferenceException |
Next Prefabの設定漏れ。Ball1〜5すべて設定したか確認 |
| 合体しても大きくならない | Next Prefabに同じ玉を入れている(Ball1にBall1など) |
| 合体した玉が箱から飛び出す | 大きい玉が壁に食い込んで押し出されている。 箱を広くするか、玉のLinear Dampingを上げる |
基礎課題全員必須
合体を完成させる:
- IDを比べる
ifと、mergedのifをBallスクリプトに入れる - 合体後の玉が1個だけであることを確認する
- 同じ玉を3つ以上ぶつけても増えないことを確認する
- 最後にCtrl + Sで保存する
標準課題時間があれば
バグを自分で再現して理解する:
- IDを比べる
ifを一時的にコメントアウトし、 玉が2個できることを確認する(確認したら戻す) Debug.Logで合体した番号を表示する- いちばん大きい紫の玉まで到達させてみる
発展課題チャレンジ
合体を演出する:
- 合体したとき、新しい玉を小さく作って
だんだん大きくする(ヒント:
transform.localScale) - レベルが上がるほど派手にする
- 合体した回数を
Debug.Logで数える
ゲームの中身ができました!
でも、まだ「うまくできたか」が数字で分かりません。 次回はスコアを画面に表示します。 合体したら点が入るようにして、ゲームらしく仕上げていきます。