コンテンツにスキップ

第6週:クリックした場所から出そう

前回は画像を取り込んで、Rigidbody 2Dで落として、Collider 2Dで床に乗せました。

  • Rigidbody 2D:動かす(重力・速度)
  • Collider 2D:形を教える(当たり判定)
  • 末尾の2Dを忘れると動かない

でも玉は1つだけで、手で置いたものでした。 今日はクリックした場所から玉が出てくるようにします。

  • Prefab(プレハブ)で玉の「設計図」を作る
  • Instantiateでスクリプトから玉を増やす
  • マウスのクリック位置をゲームの座標に変換する

玉を100個落としたいとき、100個を手で並べるのは無理です。 そこで「設計図」を1つ作っておいて、スクリプトからコピーを作る という方法をとります。

この設計図をUnityではPrefab(プレハブ)と呼びます。

Prefabの考え方
Prefabの考え方
  • スクリプトから何個でも作れる
  • Prefabを直せば、コピー全部が直る
  • ファイルとして保存されるので、他のシーンでも使える
  1. ProjectウィンドウのAssetsを右クリック
  2. Create → Folder
  3. 名前をPrefabsにする

前回作ったBallをそのままPrefabにします。 その前に、Prefabにする前提で名前を分かりやすくしておきましょう。

  1. HierarchyでBallを選択
  2. F2キーで名前をBall1に変更(レベル1の玉という意味)
  3. Inspectorで次を確認:
    • Sprite Rendererにlevel1が設定されている
    • Rigidbody 2Dが付いている
    • Circle Collider 2Dが付いている
  1. HierarchyのBall1つかんで、 ProjectウィンドウのAssets/Prefabsフォルダにドロップ
  2. PrefabsフォルダにBall1というファイルができる
  3. HierarchyのBall1の文字が青色に変わる
    (=Prefabとつながっている印)
Prefabの作成
Prefabの作成

これからスクリプトで玉を作るので、最初から置いてある玉は不要です。

  1. HierarchyのBall1を選択
  2. Deleteキーで削除

再生してみると、床だけがある状態になっています。

玉を作る役目のGameObjectを用意します。

  1. Hierarchyで右クリック → Create Empty
  2. 名前をBallSpawnerに変更
  3. Positionは(0, 0, 0)のまま

最初のバージョン:スペースキーで出す

Section titled “最初のバージョン:スペースキーで出す”

いきなりマウス対応は難しいので、まずキーを押したら真ん中から出る ものを作ります。

  1. Assets/Scriptsフォルダを右クリック
  2. Create → MonoBehaviour Script
  3. 名前をBallSpawnerにする
  4. ダブルクリックしてVisual Studioで開く
using UnityEngine;
using UnityEngine.InputSystem;
public class BallSpawner : MonoBehaviour
{
// Inspectorから玉のPrefabを設定する
public GameObject ballPrefab;
// 玉が出てくる高さ
public float spawnY = 4f;
void Update()
{
// スペースキーを押した瞬間
if (Keyboard.current.spaceKey.wasPressedThisFrame)
{
// 画面の真ん中の上に玉を作る
Vector3 spawnPos = new Vector3(0, spawnY, 0);
Instantiate(ballPrefab, spawnPos, Quaternion.identity);
}
}
}

スクリプトを取り付けてPrefabを渡す

Section titled “スクリプトを取り付けてPrefabを渡す”
  1. BallSpawner.csBallSpawnerオブジェクトにドラッグ
  2. HierarchyでBallSpawnerを選択
  3. InspectorにBall Prefabという欄が出ている
  4. Assets/Prefabs/Ball1その欄にドラッグ
PrefabをInspectorに設定
PrefabをInspectorに設定

再生ボタンを押して、スペースキーを何回か押してみてください。

玉が次々に出てきて、床に積み上がります!

スペースキーで玉が出る
スペースキーで玉が出る
コード 意味
public GameObject ballPrefab; Inspectorから設定できる玉の設計図
Keyboard.current.spaceKey スペースキーの状態
wasPressedThisFrame 押した瞬間だけtrue
Instantiate(A, B, C) 設計図Aから、位置Bに、向きCで作る
Quaternion.identity 「回転なし」を表す決まった書き方

いよいよマウス対応です。

マウスの位置と、ゲームの中の位置は単位が違います

スクリーン座標 ワールド座標
何の座標か 画面上のピクセル位置 ゲーム世界の位置
原点(0,0) 画面の左下 画面の中央(カメラの位置)
単位 ピクセル(例:1920) メートル(例:8)
使うもの マウスの位置 GameObjectのPosition
スクリーン座標とワールド座標
スクリーン座標とワールド座標

マウスの位置をそのままPositionに入れると、 玉がとんでもなく遠くに飛んでいきます。 そこで変換が必要です。

// スクリーン座標 → ワールド座標に変換する
Vector3 worldPos = Camera.main.ScreenToWorldPoint(screenPos);

Camera.mainは「MainCameraタグが付いたカメラ」を自動で見つけてくれます。

using UnityEngine;
using UnityEngine.InputSystem;
public class BallSpawner : MonoBehaviour
{
public GameObject ballPrefab;
public float spawnY = 4f;
void Update()
{
// マウスの左ボタンを押した瞬間
if (Mouse.current.leftButton.wasPressedThisFrame)
{
// 1. マウスの画面上の位置を取る
Vector2 screenPos = Mouse.current.position.ReadValue();
// 2. ゲーム世界の位置に変換する
Vector3 worldPos = Camera.main.ScreenToWorldPoint(screenPos);
// 3. 高さは固定して、横の位置だけマウスに合わせる
Vector3 spawnPos = new Vector3(worldPos.x, spawnY, 0);
// 4. 玉を作る
Instantiate(ballPrefab, spawnPos, Quaternion.identity);
}
}
}

再生して、画面のいろいろな場所をクリックしてみてください。

クリックした真上から玉が落ちてきます!

クリックで玉が出る
クリックで玉が出る

ここまでできれば、もう「遊べる」状態です。 たくさんクリックして積み上げてみましょう。

クリック連打で玉が出すぎると、動作が重くなります。 前の玉が落ちきるまで待つようにしてみましょう。

using UnityEngine;
using UnityEngine.InputSystem;
public class BallSpawner : MonoBehaviour
{
public GameObject ballPrefab;
public float spawnY = 4f;
public float waitTime = 0.5f; // 次に出せるまでの秒数
private float timer = 0f; // 経過時間
void Update()
{
// 時間を進める
timer += Time.deltaTime;
// 待ち時間が過ぎていないなら、何もしない
if (timer < waitTime)
{
return;
}
if (Mouse.current.leftButton.wasPressedThisFrame)
{
Vector2 screenPos = Mouse.current.position.ReadValue();
Vector3 worldPos = Camera.main.ScreenToWorldPoint(screenPos);
Vector3 spawnPos = new Vector3(worldPos.x, spawnY, 0);
Instantiate(ballPrefab, spawnPos, Quaternion.identity);
// タイマーをリセット
timer = 0f;
}
}
}
症状 原因と対処法
NullReferenceException が出て玉が出ない InspectorのBall Prefab欄が空。Prefabをドラッグする
玉がとんでもない場所に出る ScreenToWorldPointを使っていない
玉が画面の外に出る spawnYが大きすぎる。4くらいにする
クリックしても反応しない using UnityEngine.InputSystem; を書いたか確認
Camera.mainがnull カメラのTagがMainCameraか確認
玉が1個しか出ない UpdateではなくStartに書いていないか確認
玉が大量に出て重くなる wasPressedThisFrameを使っているか確認 (isPressedだと押している間ずっと出る)

基礎課題全員必須

クリックで玉が出るようにする:

  • Ball1のPrefabを作る
  • BallSpawnerオブジェクトとスクリプトを作る
  • InspectorでBall Prefabを設定する
  • クリックした場所の上から玉が落ちることを確認
  • 最後にCtrl + Sで保存する

標準課題時間があれば

出方を調整する:

  • waitTimeを追加して連打を防ぐ
  • spawnYをInspectorで変えて出る高さを調整
  • Debug.Logでクリック位置を表示し、 スクリーン座標とワールド座標の値を見比べる

発展課題チャレンジ

出る玉をランダムにする:

  • level2.pngを使ってBall2のPrefabも作る
  • public GameObject[] ballPrefabs;で配列にする
  • Random.Range(0, ballPrefabs.Length)で ランダムに選ぶ
  • ヒント:配列はInspectorでSizeを2にしてから設定します

今のままでは玉が床の左右からこぼれ落ちてしまいます。

次回は箱を作って玉を閉じ込め、 さらに何種類もの玉がランダムに出てくるようにします。 これで合体の準備が整います。