【Unity】ゲームに使えるシーン切り替えを実装する手順(2D)
「一つのシーンで今まで色々やってきたけど、もうちょっとゲームらしさを出したい」と思ったことはありませんか?
私自身Unityをしばらく触って動かしているうちに、ゲームらしい感じにしてみたいという欲が湧いてきたという過去があります。
その時、最初にやってみたのが複数のシーンを使ったシーン切り替えをやってみるということでした。
そこで本記事では、ゲームらしくする第一歩としてシーン切り替えに焦点を絞って、
- シーン切り替えとはどういうものか
- シーン切り替えの基本的な使い方
- 簡易的なゲームを作成してのシーン切り替えの実装
の順でご紹介いたします。
5分くらいで読めますし、ゲームを作る第一歩となるかと思いますので、ぜひご一読ください^^
※本記事の操作キャラクターには「Unity-Chan(ユニティちゃん)」を使用しています。
© Unity Technologies Japan/UCL
参考ページ)ユニティちゃん公式サイト
【導入編】Unityにおけるシーンの切り替えとは
シーンの切り替えってどんなもの?
2Dアクションゲームを例にとって考えてみると、下記の流れでゲームが構築されていることがあります。
このタイトル画面からゲーム画面への移り変わるような画面の切り替わりをシーン切り替えと呼んでいます。
それではUnityにおいて、シーン切り替えはどのように行えばいいのでしょうか。
シーン切り替え方法
シーン切り替えは、必要とする複数の画面と管理するオブジェクトを用意し、管理するオブジェクトから切り替えの指示を出すことで切り替えが行われます。
Unityにはこの指示にあたるシーンを切り替えるための関数が用意されているので、それを利用することで簡単にシーンの切り替えの実装ができます。
タイトル画面からゲーム画面へのシーン切り替えを実装
それでは、実際にタイトル画面からゲーム画面へのシーン切り替えを実装していきます。
実装の流れとしては下記になります。
- タイトル画面とゲーム画面の2つのシーンを作成
- シーン移動をさせるスクリプトを適用するための空オブジェクトを作成
- シーン切り替えをするスクリプトを作成
- シーン切り替えで読み込みを行うシーンをBuild Settingsで設定
今回使用した環境は下記になります。
- モデル:MacBook(Ratina,12inch,2017)
- OS:macOS Mojave 10.14.3
- CPU:Intel Core i7
- GPU:Intel HD Graphics 615
- Unityのバージョン:Unity 2018.3.6
また、キャラクターなどのデータは、「ユニティちゃん 2Dデータ」を使用しています。
スタート画面とゲーム画面の作成
新規プロジェクトを立ち上げ、初期の画面をタイトル画面とし「Scene_Title」、メニューバーのFile>New Sceneで作成した画面を「Scene_Game」と名前をつけます。
下記の画像のように画面上にアセットデータ内の素材とテキストを配置し、簡単なタイトル画面とゲーム画面を作成します。
テキストを配置するやり方については下記の記事を参考にしてみてください。
参考記事→)【Unity uGUI】テキスト(Text)を使いこなす基本設定の方法
空のオブジェクトの作成
タイトル画面のシーンファイルで、シーン移動のスクリプトを適用する空のGame Objectを作成します。
ヒエラルキーウィンドウでCreate>Create Emptyと選択していくことで作成することができます。
シーン切り替えのスクリプトの作成
シーンを変更するためのスクリプトファイルの作成します。
タイトル画面のシーンファイルを開き、プロジェクトウィンドウでCreate>C# Scriptと選択してファイルを作成し、名前を「SceneChange」としておきます。
スクリプトの編集画面を開き、下記のコードを記述します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement;//シーン切り替えに使用するライブラリ public class SceneChange : MonoBehaviour { // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { if (Input.GetKeyDown("s")) { SceneManager.LoadScene("Scene_Game", LoadSceneMode.Single); } } } |
コード内に記述しているUnityEngine.SceneManagementとLoadSceneを使用することでシーンの切り替えが可能です。
LoadSceneModeは、Single(デフォルト)とAdditiveがあり、それぞれ現在のシーンをアンロードする/しないに対応しています。
後者のAdditiveは、マルチシーン・エディティングを活用した開発の際に使われます。
コードの記述が終わったらスクリプトファイルを、空のゲームオブジェクトにアタッチしておきます。
今回のコードでは、キーボードの”s”キーを押すことでタイトル画面からゲーム画面にシーン切り替えするようにしています。
読み込ませるシーンの設定
メニューバーのFile>Build Settingsをクリックし、出てくるウィンドウのScenes in Buildに作成したスタート画面、ゲーム画面の2つのシーンファイルをドラッグ&ドロップします。
ここまで設定できたら実行してみましょう。
正しく設定できていれば下記のような動作になります。
【応用編】簡易的な2Dゲームでシーン切り替えを実装してみよう
シーン切り替えの使い方がわかったところで、シーン切り替えをする簡易的なゲームを作成してみます。
今回作ってみるゲームの仕様は下記になります。
- タイトル画面→ゲーム画面→クリア画面の3つの画面の遷移を行う
- 障害物を越えて、ゴールを目指す
- 穴に落ちたらスタート位置から再開
3つの画面の作成
タイトル画面は作成済みなので、ゲーム画面の拡張とクリア画面の作成を行います。
ゲーム画面は、アセットの素材を使用して下記の画像のように作ってみます。
障害物として各所にブロックや穴を配置しています。
クリアのゴールフラグ用のキャラクターを最後に配置しています。
クリア画面は、タイトル画面同様背景とクリアメッセージだけの簡単な作りにしています。
キャラクター制御などの設定
ユニティちゃんを動かすために、ユニティちゃんと床、ブロックなどにコンポーネントの追加とスクリプトの適用を行います。
設定の仕方は下記の記事のPlayerControllerのスクリプトを参考にしてみてください。
参考記事→)【Unity】2Dと3Dのジャンプ移動やアニメーションの実装方法を解説
次に、移動するユニティちゃんの動きに合わせてカメラもついていく必要があるのでカメラコントロール用のスクリプトを作成します。
プロジェクトウィンドウのCreate>C#Scriptを選択し、「CameraController」と名前をつけます。
コードは下記のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class CameraController : MonoBehaviour { GameObject player; // Start is called before the first frame update void Start() { this.player = GameObject.Find("UnityChan"); } // Update is called once per frame void Update() { //プレイヤーの位置を取得 Vector3 playerPos = this.player.transform.position; //カメラの位置をプレイヤーのX座標の位置に追従させる transform.position = new Vector3(playerPos.x, transform.position.y, transform.position.z); } } |
プレイヤーの位置を入れる変数playerPosを用意し、transform.positionで追従するようにしています。
左右の向きだけに追従するように、X座標のみplayerPosを入れています。
実行結果は下記のようになります。
穴に落下した時の判定の設定
穴に落下した際の当たり判定を設定します。
空のオブジェクトを生成し「Hole」と名前をつけます。
先ほど名前をつけた「Hole」オブジェクトに対し、Box Collider 2DとHoleのタグを作って設定します。
今回は穴に落ちた時に、ゲームの最初に戻るようにゲーム画面のシーンを呼び出すことでスタート位置に戻るようにしています。
1 2 3 4 5 6 7 |
void OnTriggerEnter2D(Collider2D col) { if(col.gameObject.tag == "Hole") { SceneManager.LoadScene("Scene_Game");//穴に落ちたら最初からスタート } } |
実行結果は下記のようになります。
ゴールについた時の判定の設定
ゴールについた時の判定のあたり判定を設定します。
ゴールにいるキャラクターに対し、Box Collider 2DとClearのタグを作って設定します。
クリア画面に遷移させるコードは下記のようになります。
ゴールにいるキャラクターに接触したら、クリア画面を呼び出すよう設定をしています。
1 2 3 4 5 6 7 8 |
void OnTriggerEnter2D(Collider2D col) { if (col.gameObject.tag == "Clear")//ゴールのオブジェクトに接触したらクリアシーンへの切り替え { SceneManager.LoadScene("Scene_Clear"); } } |
実行結果は下記のようになります。
スクリプトの適用
最終的なゲーム画面のスクリプトは下記のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement;//シーン切り替えに利用 public class PlayerController : MonoBehaviour { Rigidbody2D rb; Animator animator; float jumpForce = 500.0f; // ジャンプ時に加える力 float jumpThreshold = 2.0f; // ジャンプ中か判定するための閾値 float runForce = 30.0f; // 走り始めに加える力 float runSpeed = 5.0f; // 走っている間の速度0.5 float runThreshold = 2.0f; // 速度切り替え判定のための閾値 bool isGround = true; // 地面と接地しているか管理するフラグ int key = 0; // 左右の入力管理 string state; // プレイヤーの状態管理 string prevState; // 前の状態を保存 float stateEffect = 1; // 状態に応じて横移動速度を変えるための係数 void Start() { this.rb = GetComponent<Rigidbody2D>(); this.animator = GetComponent<Animator>(); } void Update() { GetInputKey(); // ① 入力を取得 ChangeState(); // ② 状態を変更する ChangeAnimation(); // ③ 状態に応じてアニメーションを変更する Move(); // ④ 入力に応じて移動する } void GetInputKey() { key = 0; if (Input.GetKey(KeyCode.RightArrow)) key = 1; if (Input.GetKey(KeyCode.LeftArrow)) key = -1; } void ChangeState() { // 空中にいるかどうかの判定。上下の速度(rigidbody.velocity)が一定の値を超えている場合、空中とみなす if (Mathf.Abs(rb.velocity.y) > jumpThreshold) { isGround = false; } // 接地している場合 if (isGround) { // 走行中 if (key != 0) { state = "RUN"; //待機状態 } else { state = "IDLE"; } // 空中にいる場合 } else { // 上昇中 if (rb.velocity.y > 0) { state = "JUMP"; // 下降中 } else if (rb.velocity.y < 0) { state = "FALL"; } } } void ChangeAnimation() { // 状態が変わった場合のみアニメーションを変更する if (prevState != state) { switch (state) { case "JUMP": animator.SetBool("JumpUp", true); animator.SetBool("JumpDown", false); animator.SetBool("Run", false); animator.SetBool("Idle", false); stateEffect = 0.5f; break; case "FALL": animator.SetBool("JumpDown", true); animator.SetBool("JumpUp", false); animator.SetBool("Run", false); animator.SetBool("Idle", false); stateEffect = 0.5f; break; case "RUN": animator.SetBool("Run", true); animator.SetBool("JumpDown", false); animator.SetBool("JumpUp", false); animator.SetBool("Idle", false); stateEffect = 1f; transform.localScale = new Vector3(key, 1, 1); // 向きに応じてキャラクターを反転 break; default: animator.SetBool("Idle", true); animator.SetBool("JumpDown", false); animator.SetBool("Run", false); animator.SetBool("JumpUp", false); stateEffect = 1f; break; } // 状態の変更を判定するために状態を保存しておく prevState = state; } } void Move() { // 接地している時にSpaceキー押下でジャンプ if (isGround) { if (Input.GetKeyDown(KeyCode.Space)) { this.rb.AddForce(transform.up * this.jumpForce); isGround = false; } } // 左右の移動。一定の速度に達するまではAddforceで力を加え、それ以降はtransform.positionを直接書き換えて同一速度で移動する float speedX = Mathf.Abs(this.rb.velocity.x); if (speedX < this.runThreshold) { this.rb.AddForce(transform.right * key * this.runForce * stateEffect); //未入力の場合は key の値が0になるため移動しない } else { this.transform.position += new Vector3(runSpeed * Time.deltaTime * key * stateEffect, 0, 0); } } //着地判定 void OnTriggerEnter2D(Collider2D col) { if (col.gameObject.tag == "Ground") { if (!isGround) isGround = true; } if(col.gameObject.tag == "Hole") { SceneManager.LoadScene("Scene_Game");//穴に落ちたら最初からスタート } if (col.gameObject.tag == "Clear")//ゴールのオブジェクトに接触したらクリアシーンへの切り替え { SceneManager.LoadScene("Scene_Clear"); } } void OnTriggerStay2D(Collider2D col) { if (col.gameObject.tag == "Ground") { if (!isGround) isGround = true; } } } |
クリア画面のスクリプトは下記のようになります。
タイトル画面とほぼ一緒ですが、押すキーを”r”としています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement;//シーン切り替えに使用するライブラリ public class ClearScene : MonoBehaviour { // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { if (Input.GetKeyDown("r")) { SceneManager.LoadScene("Scene_Title"); } } } |
タイトル画面からクリア画面までの実行した際の動きは下記のようになります。
まとめ
いかがでしたでしょうか。
今回はシーン切り替えについて解説していきました。
ゲームらしさを出すためにシーン切り替えは重要な要素になりますので、実際に色々試しながら実装をしてみてくださいね!
この記事が、Unityを学んでいる人の参考になれば幸いです。
合わせて読んでおきたいUnityの関連記事)
- 【Unity 入門】2時間で作るユニティちゃんRunゲーム!
- 【Unity入門】ゲーム開発ができるようになる基礎知識まとめ
- Unity Shader Graphの使い方を分かりやすく解説!シェーダーとは?
この記事はいかがでしたか?
もし「参考になった」「面白かった」という場合は、応援シェアお願いします!