Unity(C#)初心者・入門者向けチュートリアル ひよこのたまご

AndroidやiOS向けアプリを簡単に作れるゲーム開発環境Unity(ユニティ)の使い方を、チュートリアル方式で一緒に学びましょう!

【Unity8】タイトル・クリア・ゲームオーバー画面を作成!uGUI, Canvas, Text, Image【横スクロールユニティちゃん13】

Unity5.1.0f3 Personal(2015年6月)

f:id:hiyotama:20150618122504p:plain


このコンテンツは、『ユニティちゃんライセンス』で提供されています

ユニティちゃんライセンス

前回の続きです〜

今回は、タイトル画面からステージ紹介画面に移り、ステージ画面に移り、死んだらゲームオーバー、ステージをクリアしたら次のステージ、、、という感じの画面を作っていって、ゲームを回していきたいと思います〜

基本的には以下エッセンスと同じ内容ですので、ご参照下さい〜

hiyotama.hatenablog.com

【目標】ゲームがちゃんと回るようにする

①タイトル画面作成

「Title」、「Stage1」「Main」とSceneを作っていきます〜

既に「Main」Sceneは作ってありますので、まずはタイトル画面を作成しましょう〜


f:id:hiyotama:20150619110424p:plain
File > New Scene


SceneができたらCtrl + sで即Saveしましょう〜名前はTitleにします〜

f:id:hiyotama:20150619110628p:plain


カメラの背景色を変え、適当な文字を作成します〜
今回はファミコン風のフリーフォントを使います〜こちらのサイトのPixelMPlusというフォントを使わさせて頂きます〜ありがとうございます!


PixelMplus(ピクセル・エムプラス) ‥ 8bitビットマップふうフリーフォント - itouhiroはてなブログ


ダウンロードが完了したら、ttfという拡張子のファイルをProjectビューにImportします〜


f:id:hiyotama:20150619112442p:plain
ドラッグ&ドロップ!


f:id:hiyotama:20150619112910p:plain
実際の画面


f:id:hiyotama:20150619112720p:plain
Canvas設定


f:id:hiyotama:20150619112805p:plain
Text設定1


f:id:hiyotama:20150619112850p:plain
Text設定2


あとはMainCameraに、画面をクリックした時に「Stage1」Sceneを呼び出すスクリプトを付ければOKです〜以下ソースです〜

using UnityEngine;
using System.Collections;

public class CallStage1Script : MonoBehaviour {

	void Update ()
	{
		if (Input.GetMouseButtonDown (0)) {
			Application.LoadLevel("Stage1");
		}
	}
}

CallStage1Script.cs


②Stage1画面作成
続いてStage1画面を作りましょう〜やり方は先ほどと全く同じです〜Sceneを作成し、「Stage1」という名前でSceneをセーブし、uGUIのTextで文字を書きます〜

そして、今回はStageの紹介画像を貼り付けましょう〜「Main」Sceneの適当な場面を画面キャプチャに撮ります〜


f:id:hiyotama:20150619115203p:plain
画面キャプチャ!


ユニティちゃんやライフゲージが必要ない時は、非アクティブ状態にします〜


f:id:hiyotama:20150619115336p:plain
チェックを外して非アクティブ!


f:id:hiyotama:20150619115350p:plain
これを採用!


Stage1シーンに戻り、HierarchyビューのCreate > UI > Imageを選択し、InspectorビューのImageコンポーネントのSource Imageに、先ほど撮ったキャプチャを指定します〜


f:id:hiyotama:20150619115634p:plain
Image情報


Canvas情報とText情報は先ほどと同じ感じです〜


f:id:hiyotama:20150619115740p:plain


それでは2秒経ったら「Main」Sceneへ映る処理を作成し、MainCameraに取り付けていきましょう〜以下ソースです〜

using UnityEngine;
using System.Collections;

public class CallMainScript : MonoBehaviour {

	// Use this for initialization
	IEnumerator Start () {
		yield return new WaitForSeconds(2);
		Application.LoadLevel("Main");
	}
}

CallMainScript.cs


Startメソッドの戻り値にIEnumeratorと書くことでコルーチンにしています〜コルーチンについては以下エッセンスをご参照下さい〜


hiyotama.hatenablog.com


WaitForSecondsで2秒待って、「Main」Sceneを呼んでいます〜


③ゲーム画面にゲームオーバー機能を付ける

それではまずは「Main」Sceneにゲームオーバーを付けていきましょう〜ライフが0になるか、穴に落ちたらゲームオーバーです〜

まずはゲームオーバーのTextを作成します〜以下の設定にして、非アクティブ状態にしておきましょう〜


f:id:hiyotama:20150619144415p:plain
チェックを外して非アクティブに

f:id:hiyotama:20150619132906p:plain
ユニティちゃんがやられたら表示


それではユニティちゃんのライフが無くなった時を判定できる、LifeScriptに加筆していきます〜

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class LifeScript : MonoBehaviour {
	
	RectTransform rt;
//********** 開始 **********//
	public GameObject unityChan; //ユニティちゃん
	public GameObject explosion; //爆発アニメーション
	public Text gameOverText; //ゲームオーバーの文字
	private bool gameOver = false; //ゲームオーバー判定
//********** 終了 **********//
	void Start ()
	{
		rt = GetComponent<RectTransform>();
	}
//********** 開始 **********//
	void Update ()
	{
		//ライフが0以下になった時、
		if (rt.sizeDelta.y <= 0) {
			//ゲームオーバー判定がfalseなら爆発アニメーションを生成
			//GameOverメソッドでtrueになるので、1回のみ実行
			if (gameOver == false) {
				Instantiate (explosion, unityChan.transform.position + new Vector3 (0, 1, 0), unityChan.transform.rotation);
			}
			//ゲームオーバー判定をtrueにし、ユニティちゃんを消去
			GameOver ();
		}
		//ゲームオーバー判定がtrueの時、
		if (gameOver) {
			//ゲームオーバーの文字を表示
			gameOverText.enabled = true;
			//画面をクリックすると
			if (Input.GetMouseButtonDown (0)) {
				//タイトルへ戻る
				Application.LoadLevel("Title");
			}
		}
	}
//********** 終了 **********//
	
	public void LifeDown (int ap)
	{
		rt.sizeDelta -= new Vector2 (0,ap);
	}

	public void LifeUp (int hp)
	{
		rt.sizeDelta += new Vector2 (0,hp);

		if (rt.sizeDelta.y > 240f) {
			rt.sizeDelta = new Vector2 (51f, 240f);
		}
	}

//********** 開始 **********//
	public void GameOver ()
	{
		gameOver = true;
		Destroy(unityChan);
	}
//********** 終了 **********//
}

LifeScript.cs


まずはpublic変数であるunityChanとExplosion、gameOverTextにオブジェクトを設定していきます〜


f:id:hiyotama:20150619145034p:plain
ドラッグ&ドロップ!


流れとしては、
①ライフが0以下になった時に爆発アニメーションを生成し、Unityちゃんを消去する
②ゲームオーバーの文字を表示し、画面をクリックするとタイトルへ戻れる状態にしておく


といった感じです〜


続いてユニティちゃんが穴に落ちた時の処理も作成していきましょう〜こちらはPlayerScriptに加筆していきます〜

using UnityEngine;
using System.Collections;


public class PlayerScript : MonoBehaviour {
	
	public float speed = 4f;
	public float jumpPower = 700;
	public LayerMask groundLayer;
	public GameObject mainCamera;
	public GameObject bullet;
//********** 開始 **********//
	public LifeScript lifeScript;
//********** 終了 **********//
	
	private Rigidbody2D rigidbody2D;
	private Animator anim;
	private bool isGrounded;
	private Renderer renderer;
	
	void Start () {
		anim = GetComponent<Animator>();
		rigidbody2D = GetComponent<Rigidbody2D>();
		renderer = GetComponent<Renderer>();
	}

	void Update ()
	{
		isGrounded = Physics2D.Linecast (
			transform.position + transform.up * 1,
			transform.position - transform.up * 0.05f,
			groundLayer);
		
		if (Input.GetKeyDown ("space")) {
			if (isGrounded) {
				anim.SetTrigger ("Jump");
				isGrounded = false;
				rigidbody2D.AddForce (Vector2.up * jumpPower);
			}
		}
		
		float velY = rigidbody2D.velocity.y;
		bool isJumping = velY > 0.1f ? true : false;
		bool isFalling = velY < -0.1f ? true : false;
		anim.SetBool ("isJumping", isJumping);
		anim.SetBool ("isFalling", isFalling);
		
		if (Input.GetKeyDown ("left ctrl")) {
			anim.SetTrigger ("Shot");
			Instantiate (bullet, transform.position + new Vector3 (0f, 1.2f, 0f), Quaternion.identity);
		}
//********** 開始 **********//
		//現在のカメラの位置から8低くした位置を下回った時
		if (gameObject.transform.position.y < Camera.main.transform.position.y - 8) {
			//LifeScriptのGameOverメソッドを実行する
			lifeScript.GameOver();
		}
//********** 終了 **********//
	}
	
	void FixedUpdate ()
	{
		float x = Input.GetAxisRaw ("Horizontal");
		if (x != 0) {
			rigidbody2D.velocity = new Vector2 (x * speed, rigidbody2D.velocity.y);
			Vector2 temp = transform.localScale;
			temp.x = x;
			transform.localScale = temp;
			anim.SetBool ("Dash", true);
			if (transform.position.x > mainCamera.transform.position.x - 4) {
				Vector3 cameraPos = mainCamera.transform.position;
				cameraPos.x = transform.position.x + 4;
				mainCamera.transform.position = cameraPos;
			}
			Vector2 min = Camera.main.ViewportToWorldPoint(new Vector2(0, 0));
			Vector2 max = Camera.main.ViewportToWorldPoint(new Vector2(1, 1));
			Vector2 pos = transform.position;
			pos.x = Mathf.Clamp(pos.x, min.x + 0.5f, max.x);
			transform.position = pos;
		} else {
			rigidbody2D.velocity = new Vector2 (0, rigidbody2D.velocity.y);
			anim.SetBool ("Dash", false);
		}
	}

	void OnCollisionEnter2D (Collision2D col)
	{
		if (col.gameObject.tag == "Enemy") {
			StartCoroutine ("Damage");
		}
	}
	
	IEnumerator Damage ()
	{
		gameObject.layer = LayerMask.NameToLayer("PlayerDamage");
		int count = 10;
		while (count > 0){
			renderer.material.color = new Color (1,1,1,0);
			yield return new WaitForSeconds(0.05f);
			renderer.material.color = new Color (1,1,1,1);
			yield return new WaitForSeconds(0.05f);
			count--;
		}
		gameObject.layer = LayerMask.NameToLayer("Player");
	}
}

PlayerScript.cs


public変数lifeScriptを作成したので、いつも通り指定していきます〜


f:id:hiyotama:20150619145549p:plain
ドラッグ&ドロップ!


ユニティちゃんが現在のMain Cameraの高さより8低い位置を下回った時、つまり画面外に出た時、LifeScriptのGameOverメソッドが実行され、ユニティちゃんが消去され、GameOverの文字が出てきます〜


④敵が画面外に出た時の処理もついでに
敵が画面外に出た時に消去する処理もついでに実装します〜Enemy1Scriptに加筆していきます〜

using UnityEngine;
using System.Collections;

public class Enemy1Script : MonoBehaviour {
	
	Rigidbody2D rigidbody2D;
	public int speed = -3;
	public GameObject explosion;
	public int attackPoint = 10;
	public GameObject item;
	
	private LifeScript lifeScript;
	private const string MAIN_CAMERA_TAG_NAME = "MainCamera";
	private bool _isRendered = false;
	
	void Start () {
		rigidbody2D = GetComponent<Rigidbody2D>();
		lifeScript = GameObject.FindGameObjectWithTag("HP").GetComponent<LifeScript>();
	}
	
	void Update ()
	{
		if (_isRendered) {
			rigidbody2D.velocity = new Vector2 (speed, rigidbody2D.velocity.y);
		}
//********** 開始 **********//
		if (gameObject.transform.position.y < Camera.main.transform.position.y - 8 ||
		gameObject.transform.position.x < Camera.main.transform.position.x - 10) {
			Destroy(gameObject);
		}
//********** 終了 **********//
	}
	
	void OnTriggerEnter2D (Collider2D col)
	{
		if (_isRendered) {
			if (col.tag == "Bullet") {
				Destroy (gameObject);
				Instantiate (explosion, transform.position, transform.rotation);
				if (Random.Range (0, 4) == 0) {
					Instantiate (item, transform.position, transform.rotation);
				}
			}
		}
	}

	void OnCollisionEnter2D (Collision2D col)
	{
		if (col.gameObject.tag == "UnityChan") {
			lifeScript.LifeDown (attackPoint);
		}
	}
	
	void OnWillRenderObject()
	{
		if(Camera.current.tag == MAIN_CAMERA_TAG_NAME){
		_isRendered = true;
		}
	}
}

Enemy1Script.cs


先ほどPlayerScriptで実装した処理の応用です〜ユニティちゃんは画面より左に行くことはないですが、敵キャラはいってしまうので、そうなった時にもDestroyするようにしています〜


⑤ゲーム画面にゲームクリアー機能を付ける
それでは最後にゲームクリアーの処理を追加していきます〜


まずはゲームクリアーテキストを作成しましょう〜ゲームオーバーテキストと同じく、Textコンポーネントは非アクティブ化しておきます〜


f:id:hiyotama:20150619153443p:plain
GameClearテキストの情報 Textコンポーネントは非アクティブ


f:id:hiyotama:20150619153546p:plain
画面に映るとこんな感じ


続いてここを超えたらゲームクリアーですよ〜というオブジェクト、ClearZoneオブジェクトを作成します〜HierarchyビューからCreate > Create Emptyを選択し、名前をClearZoneとします〜


f:id:hiyotama:20150619153824p:plain


BoxCollider2Dを付けて、以下のような設定にします〜ClearZoneという名前のタグを作成し、付けるのを忘れないで下さい〜


f:id:hiyotama:20150619154011p:plain
サイズは大きめ Is Triggerをtrue タグを忘れずに


f:id:hiyotama:20150619154110p:plain
この緑の枠を超えたらゲームクリアー


それではPlayerScriptに加筆していきます〜

using UnityEngine;
using System.Collections;
//********** 開始 **********//
using UnityEngine.UI;
//********** 開始 **********//

public class PlayerScript : MonoBehaviour {
	
	public float speed = 4f;
	public float jumpPower = 700;
	public LayerMask groundLayer;
	public GameObject mainCamera;
	public GameObject bullet;
	public LifeScript lifeScript;
	
	private Rigidbody2D rigidbody2D;
	private Animator anim;
	private bool isGrounded;
	private Renderer renderer;
//********** 開始 **********//
	private bool gameClear = false; //ゲームクリアーしたら操作を無効にする
	public Text clearText; //ゲームクリアー時に表示するテキスト
//********** 終了 **********//
	
	void Start () {
		anim = GetComponent<Animator>();
		rigidbody2D = GetComponent<Rigidbody2D>();
		renderer = GetComponent<Renderer>();
	}

	void Update ()
	{
		isGrounded = Physics2D.Linecast (
			transform.position + transform.up * 1,
			transform.position - transform.up * 0.05f,
			groundLayer);
//********** 開始 **********//
		//ジャンプさせない
		if (!gameClear) {
//********** 終了 **********//
			if (Input.GetKeyDown ("space")) {
				if (isGrounded) {
					anim.SetTrigger ("Jump");
					isGrounded = false;
					rigidbody2D.AddForce (Vector2.up * jumpPower);
				}
			}
//********** 開始 **********//
		}
//********** 終了 **********//
		
		float velY = rigidbody2D.velocity.y;
		bool isJumping = velY > 0.1f ? true : false;
		bool isFalling = velY < -0.1f ? true : false;
		anim.SetBool ("isJumping", isJumping);
		anim.SetBool ("isFalling", isFalling);
//********** 開始 **********//
		//弾を打たせない、ゲームオーバーにさせない
		if (!gameClear) {
//********** 終了 **********//
			if (Input.GetKeyDown ("left ctrl")) {
				anim.SetTrigger ("Shot");
				Instantiate (bullet, transform.position + new Vector3 (0f, 1.2f, 0f), Quaternion.identity);
			}
		
			if (gameObject.transform.position.y < Camera.main.transform.position.y - 8) {
				lifeScript.GameOver ();
			}
//********** 開始 **********//
		}
//********** 終了 **********//
	}
	
	void FixedUpdate ()
	{
//********** 開始 **********//
		//左右に移動させない MainCameraを動かさない
		if (!gameClear) {
//********** 終了 **********//
			float x = Input.GetAxisRaw ("Horizontal");
			if (x != 0) {
				rigidbody2D.velocity = new Vector2 (x * speed, rigidbody2D.velocity.y);
				Vector2 temp = transform.localScale;
				temp.x = x;
				transform.localScale = temp;
				anim.SetBool ("Dash", true);
				if (transform.position.x > mainCamera.transform.position.x - 4) {
					Vector3 cameraPos = mainCamera.transform.position;
					cameraPos.x = transform.position.x + 4;
					mainCamera.transform.position = cameraPos;
				}
				Vector2 min = Camera.main.ViewportToWorldPoint (new Vector2 (0, 0));
				Vector2 max = Camera.main.ViewportToWorldPoint (new Vector2 (1, 1));
				Vector2 pos = transform.position;
				pos.x = Mathf.Clamp (pos.x, min.x + 0.5f, max.x);
				transform.position = pos;
			} else {
				rigidbody2D.velocity = new Vector2 (0, rigidbody2D.velocity.y);
				anim.SetBool ("Dash", false);
			}
//********** 開始 **********//
		} else {
			//クリアーテキストを表示
			clearText.enabled = true;
			//アニメーションは走り
			anim.SetBool ("Dash", true);
			//右に進み続ける
			rigidbody2D.velocity = new Vector2 (speed, rigidbody2D.velocity.y);
			//5秒後にタイトル画面へ戻るCallTitleメソッドを呼び出す
			Invoke("CallTitle", 5);
		}
//********** 終了 **********//
	}

	void OnCollisionEnter2D (Collision2D col)
	{
		if (!gameClear) {
			if (col.gameObject.tag == "Enemy") {
				StartCoroutine ("Damage");
			}
		}
	}
	
	IEnumerator Damage ()
	{
		gameObject.layer = LayerMask.NameToLayer("PlayerDamage");
		int count = 10;
		while (count > 0){
			renderer.material.color = new Color (1,1,1,0);
			yield return new WaitForSeconds(0.05f);
			renderer.material.color = new Color (1,1,1,1);
			yield return new WaitForSeconds(0.05f);
			count--;
		}
		gameObject.layer = LayerMask.NameToLayer("Player");
	}
//********** 開始 **********//
	void OnTriggerEnter2D (Collider2D col)
	{
		//タグがClearZoneであるTriggerにぶつかったら
		if (col.tag == "ClearZone") {
			//ゲームクリアー
			gameClear = true;
		}
	}
	
	void CallTitle ()
	{
		//タイトル画面へ
		Application.LoadLevel("Title");
	}
//********** 終了 **********//
}

PlayerScript.cs


public変数であるClearTextを指定してあげます〜


f:id:hiyotama:20150619154651p:plain
ドラッグ&ドロップ!


gameClearフラグがtrueになった時、ジャンプ・ショット・移動と全ての操作を無効にし、MainCameraの動きも止め、ユニティちゃんが自動で右に進むようにしています〜

Invokeメソッドは、指定した秒数後に指定したメソッドを実行します〜今回は5秒後にタイトル画面を呼び出すCallTitleメソッドを呼び出しています〜


【結果】


f:id:hiyotama:20150619155027p:plain
タイトル画面をタップし


f:id:hiyotama:20150619155048p:plain
ステージ紹介画面を表示し


f:id:hiyotama:20150619155129p:plain
ゲーム開始 ライフがなくなると

f:id:hiyotama:20150619155208p:plain
ゲームオーバー 穴に落ちても


f:id:hiyotama:20150619155244p:plain
ゲームオーバー クリアー地点まで進むと


f:id:hiyotama:20150619155348p:plain
ゲームクリアーの文字 ユニティちゃんは画面右へ移動


f:id:hiyotama:20150619155027p:plain
ゲームオーバー後クリックかクリアー後5秒でタイトルへ


敵キャラ、アイテム、ステージを増やしたり、ユニティちゃんの武器を変更したり、ボスを作ったり・・・アイディア次第でいくらでも面白くしていけるかと思いますが、とりあえずゲームとして回るような形にはなったかと思います〜


それでは、今回はここまでです〜

ありがとうございました〜


【Unity開発8】ユニティちゃんを表示させる【横スクロールユニティちゃん1】

【Unity開発8】ユニティちゃんを歩かせる【横スクロールユニティちゃん2】

【Unity開発8】カメラにユニティちゃんを追いかけさせる【横スクロールユニティちゃん3】

【Unity開発8】ユニティちゃんをジャンプさせる【横スクロールユニティちゃん4】

【Unity開発8】ユニティちゃんバスターで攻撃する【ユニティちゃん横スクロール5】

【Unity開発8】走っている時やジャンプ中にも弾を撃つ【横スクロールユニティちゃん6】

【Unity開発8】弾を当てて敵を倒す【横スクロールユニティちゃん7】

【Unity開発8】uGUIでライフを作り、ダメージを実装する【横スクロールユニティちゃん8】

【Unity開発8】ダメージを食らった時、一定時間無敵状態にする【横スクロールユニティちゃん9】

【Unity開発8】アイテムを取得して体力回復する【横スクロールユニティちゃん10】

【Unity開発8】敵キャラを倒した時にアイテムを落とさせる【横スクロールユニティちゃん11】

【Unity開発8】Main Cameraに映るまで敵キャラを待機させておく【横スクロールユニティちゃん12】

【Unity開発8】タイトル・ステージ紹介・ゲームオーバー・ゲームクリアー画面を作る【横スクロールユニティちゃん13】

【Unity開発8】バーチャルパッドを付けてモバイル対応する【横スクロールユニティちゃん14】