コンテンツにスキップ

第8週:同じもの同士を合体させよう

前回は箱を作り、6種類のPrefabを用意して、 ランダムな玉が出るようにしました。

  • 配列で複数のPrefabをまとめた
  • Random.Rangeでランダムに選んだ
  • 画像を変えたらColliderの大きさも合わせる
  • 玉に「自分が何番か」を覚えさせる
  • OnCollisionEnter2Dでぶつかったことを知る
  • 同じ番号同士が合体して1つ大きくなるようにする
  • わざとバグのあるコードを書いて、原因を突き止める

プログラムを書く前に、日本語でルールを書き出します。 これはプロの開発者もやる大事な作業です。

合体のしくみ
合体のしくみ

玉自身に「自分は何番か」「合体したら何になるか」を持たせます。

  1. Assets/Scriptsを右クリック
  2. Create → MonoBehaviour Script
  3. 名前をBallにする
using UnityEngine;
public class Ball : MonoBehaviour
{
// この玉の番号(1〜6)
public int level = 1;
// 合体してできる玉のPrefab(いちばん大きい玉はNoneにする)
public GameObject nextPrefab;
}

まだ何もしません。データを持たせただけです。

  1. ProjectウィンドウでAssets/Prefabsを開く
  2. Ball1Ball66つまとめて選択
    (Ctrlを押しながらクリック、またはShiftで範囲選択)
  3. Add Component → Ballを追加
    ※まとめて追加できない場合は、1つずつ開いて追加してください

次に、1つずつ中身を設定します。

Prefab Level Next Prefab
Ball1 1 Ball2
Ball2 2 Ball3
Ball3 3 Ball4
Ball4 4 Ball5
Ball5 5 Ball6
Ball6 6 None(空のまま)
Prefabへの設定
Prefabへの設定

Unityには「ぶつかった瞬間に自動で呼ばれるメソッド」があります。

void OnCollisionEnter2D(Collision2D collision)
{
// ここに、ぶつかったときの処理を書く
Debug.Log("何かにぶつかった!");
}
メソッド 呼ばれるタイミング
OnCollisionEnter2D ぶつかった瞬間(1回だけ)
OnCollisionStay2D ぶつかっている(毎フレーム)
OnCollisionExit2D 離れた瞬間(1回だけ)
void OnCollisionEnter2D(Collision2D collision)
{
// ぶつかった相手のGameObject
GameObject otherObject = collision.gameObject;
// 相手のBallスクリプトを取り出す
Ball other = otherObject.GetComponent<Ball>();
// 相手が玉でなければ、otherはnullになる
if (other == null)
{
Debug.Log("壁か床にぶつかった");
return;
}
Debug.Log("玉にぶつかった!相手の番号は " + other.level);
}

まず素朴に書いてみよう(バグ入り)

Section titled “まず素朴に書いてみよう(バグ入り)”

いきなり完成版を書かず、素直に書いてバグを体験します。 バグの原因が分かると、完成版の意味が理解できます。

using UnityEngine;
public class Ball : MonoBehaviour
{
public int level = 1;
public GameObject nextPrefab;
void OnCollisionEnter2D(Collision2D collision)
{
Ball other = collision.gameObject.GetComponent<Ball>();
// 相手が玉でないなら何もしない
if (other == null) return;
// 番号が違うなら合体しない
if (other.level != level) return;
// いちばん大きい玉は合体しない
if (nextPrefab == null) return;
// 2つの真ん中の位置を計算
Vector3 center = (transform.position + other.transform.position) / 2f;
// 次の玉を作って、元の2つを消す
Instantiate(nextPrefab, center, Quaternion.identity);
Destroy(other.gameObject);
Destroy(gameObject);
}
}

同じ番号の玉を2つぶつけてみてください。

合体しました。……でも、よく見てください。

バグ:玉が2個できる
バグ:玉が2個できる

基礎課題全員必須

合体するところまで作る:

  • Ballスクリプトを作り、6つのPrefabに付ける
  • 各PrefabのLevelとNext Prefabを設定する
  • 同じ玉同士がぶつかったら合体することを確認する
  • 最後にCtrl + Sで保存する

標準課題時間があれば

バグをはっきり確かめる:

  • 合体させたあと、HierarchyでCloneがいくつ増えたか数える
  • OnCollisionEnter2Dの先頭にDebug.Log("ぶつかった");を書き、 1回の衝突で何回表示されるか確認する

発展課題チャレンジ

同じ番号の玉を3つ以上まとめてぶつけて、何が起きるか観察する。 玉が2個できるのとは別の問題が起きていないか、気づいたことをメモしておく。

合体はしましたが、玉が2個できるバグが残ったままです。

次回はこのバグを直します。 「2つのうちどちらが処理を担当するか」を決める方法を学び、 さらに3つ同時にぶつかったときの問題も片づけて、合体を完成させます。