Unity 玉転がし#02 アイテムと障害物を作る

チュートリアル

Unity チュートリアル 玉転がしゲーム作成の第2回目です。

今回はゲームクリアのためのアイテムと、ゲーム性を出すための障害物を作成します。

この工程を通して、オブジェクト同士が衝突した時の処理を追加する方法を覚えましょう。

それでは、以下、解説。

この記事の Unity バージョンは、2019.2.5f1 です。

1.アイテムを作る

では、ゲームクリアのためのアイテムを作成しましょう。

  1. キューブを作る
    ・Create → 3D Object → Cube を選択、名前を「Item」とします。
    ・position を 0, 1, 3 に設定します。
  2. 色を変える
    ・好きな色に変更してください。
  3. コライダーをトリガーにする
    ・Add Component → Physics → Rigidbody を選択します。
    ・Rigidbody の Is Kinematic にチェックを入れます。
    ・Box Collider の Is Trigger にチェックを入れます。
  4. スクリプトをアタッチする
    ・Scriptsフォルダを右クリックし、Create → C# Script を選択、名前を「Item」とします。
    ・ヒエラルキーで Item を選択し、Add Component → Scripts → Item でアタッチします。
  5. プレハブ化する
    ・プロジェクトウィンドウで Create → Folder を選択、名前を「Prefabs」とします。
    ・ヒエラルキーから Item を Prefabs フォルダにドラッグ&ドロップします。

Item スクリプトに、下記のコードを追加します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Item : MonoBehaviour
{
	private void Update()
	{
		// 回転アニメ。
		transform.Rotate( new Vector3( 15, 30, 45 ) * Time.deltaTime );
	}

	private void OnTriggerEnter( Collider other )
	{
		// プレイヤーと接触したら削除する。
		if ( other.CompareTag( "Player" ) )
		{
			Destroy( gameObject );
		}
	}
}

OnTriggerEnter は他のコライダーがトリガーに侵入したときに通知されるイベントです。

上のスクリプトでは、侵入したコライダーの持ち主がプレイヤーかどうかをタグで判定しています。

前回作成した Player にタグを設定して判定が通るようにしましょう。

タグ設定

ここで、一度実行して確認。

アイテム取得

アイテムがプレイヤーと衝突したときにちゃんと消えていますね。

では次へ。

2.障害物を作る

次は、衝突するとゲームオーバーになる障害物を作成します。

  1. キューブを作る
    ・Create → 3D Object → Cube を選択、名前を「Block」とします。
    ・position を 0, 0.5, 0 に設定します。
  2. 色を変える
    ・好きな色に変更してください。
  3. スクリプトを作る
    ・Scriptsフォルダを右クリックし、Create → C# Script を選択、名前を「Block」とします。
    ・ヒエラルキーで Block を選択し、Add Component → Scripts → Blockでアタッチします。
  4. プレハブ化する
    ・ヒエラルキーから Block を Prefabs フォルダにドラッグ&ドロップします。

Block スクリプトに、下記のコードを追加します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Block : MonoBehaviour
{
	private void OnCollisionEnter( Collision collision )
	{
		if ( collision.gameObject.CompareTag( "Player" ) )
		{
			Destroy( collision.gameObject );
			Debug.Log( "GameOver!" );
		}
	}
}

はい。こうなりました。

ブロック


リザルト用のシーンを追加したあとで、ここを書き換えてシーンの遷移を実装します。

3.リザルトを作る

リザルトを作る前に、シーン切り替えの準備として現在のシーン名を変更します。

Unity のメニューから File → Save As … をクリックし、「Main」という名前で保存します。

では、リザルトシーンを作ります。

Unity のメニューから File → New Scene をクリックし、 Result という名前で保存してください。

次に、Result から Main に戻れるようにリスタートボタンを追加します。

手順は下記です。

  1. Canvas を追加する
    ・Create → UI → Canvas で作成します。
    ・Canvas Scaler の UI Scale Mode を Scale With Screen Size にします。
    ・Reference Resolution を x 1920 y 1080 にします。
    ・Screen Match Mode を Expand にします。
  2. Button を追加する
    ・Create → UI → Button でボタンを作成します。
    ・PosX, PosY, PosZ はすべて 0、Width 300, Height 160 にします。
    ・Text に Restart と入れ、Font Size 50 にします。
  3. Button にスクリプトをアタッチする
    ・Scriptsフォルダを右クリックし、Create → C# Script を選択、名前を「RestartButton」とします。
    ・Button に RestartButton をアタッチします。
  4. Main Camera と Directional Light を削除する

こんな見た目になります。No Cameras rendering と表示されますが問題ないです。

ライト&カメラ削除

RestartButton スクリプトに、下記のコードを追加します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using UnityEngine.SceneManagement;

public class RestartButton : MonoBehaviour
{
	public void LoadMainScene()
	{
		// Main シーンを読み込む
		SceneManager.LoadScene( "Main" );
	}
}

スクリプトが出来たら、ボタンをクリックしたときに LoadMainScene が呼ばれるように設定します。

Button のOn Click イベントに LoadMainScene をリンクさせます。

OnClick設定

つぎはシーン切り替えのため、Main と Result を Build Settings に追加します。

Build Settings にシーンを追加する方法は、こちらをどうぞ。

最後に、Block スクリプトを下記のように修正して Result に遷移するようにします。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using UnityEngine.SceneManagement;

public class Block : MonoBehaviour
{
	private void OnCollisionEnter( Collision collision )
	{
		if ( collision.gameObject.CompareTag( "Player" ) )
		{
			Destroy( collision.gameObject );
			// Result シーンを読み込む
			SceneManager.LoadSceneAsync( "Result", LoadSceneMode.Additive );

			// ゲーム進行を停止する。
			Time.timeScale = 0; 

			// リスタート時に再開するようにセット。
			SceneManager.sceneUnloaded += scene => Time.timeScale = 1;
		}
	}
}

Main シーンを開いて、ゲームを実行してみましょう。

サイクル

Block に衝突したら Result に遷移、Restart ボタンで Main に戻りましたね。

ゲームサイクルが出来上がりつつあります。

4.アイテムを全部取ったらリザルトに遷移する

リザルトへの遷移ができるようになりましたので、ゲームクリアも実装しましょう。

ゲームクリアの条件は、シーン上にアイテムがなくなったときです。

なので、Item と衝突したときに残りアイテム数を調べて、クリアかどうか判定するようにしてみます。

まずは、アイテム用のタグを追加します。

Unity メニューから Edit → Project Settings → Tags and Layers の Tags に Item を追加します。

Item のプレハブを選択し、Tag を Item に設定します。

Itemタグ追加

タグの設定が出来たら、Item スクリプトを下記のように変更します。

using System; // 追加
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement; // 追加

public class Item : MonoBehaviour
{
	private void Update()
	{
		// 回転アニメ。
		transform.Rotate( new Vector3( 15, 30, 45 ) * Time.deltaTime );
	}

	private void OnTriggerEnter( Collider other )
	{
		// プレイヤーと接触したら削除する。
		if ( other.CompareTag( "Player" ) )
		{
			// 自分自身以外の残っているアイテムを検索する。
			var items = Array.FindAll( GameObject.FindGameObjectsWithTag( "Item" ), obj => obj != gameObject );

			// 残りアイテムが0だったら、Resultに遷移する。
			if ( items.Length == 0 )
			{
				SceneManager.LoadSceneAsync( "Result", LoadSceneMode.Additive );

				// ゲーム進行を停止する。
				Time.timeScale = 0; 

				// リスタート時に再開するようにセット。
				SceneManager.sceneUnloaded += scene => Time.timeScale = 1;
			}

			Destroy( gameObject );
		}
	}
}

これでゲームクリア判定ができるようになりました!

適当にアイテムを複数配置してゲームを実行してみてください。

ゲームクリア

今回はここまでです。

次回はプレイタイム、ベストタイムを表示する機能を実装します。

以上。 おしまい!

Item のコライダー関連の補足

Rigidbody の Is Kinematic にチェックを入れると、物理エンジンの影響を受けなくなります

つまり、重力はかからないし、他のオブジェクトと衝突したときの反発も無視されます。

Box Collider の Is Trigger にチェックを入れると、コライダー同士がすり抜けるようになります。

ねこくん
ねこくん

これって Rigidbody いらないのでは?

すり抜けちゃうし、重力もいらないんだったら

確かに、この場合、Rigidbody がなくても表面上の動作は似た感じになります。

では、なぜアタッチしているかというと、理由は下記の 2つです。
① Rigidbody がないと、トリガーイベントが通知されない。
② Static Collider を動かすと、物理エンジンのパフォーマンスが低下する。

①について
Item ではトリガーに侵入したときにオブジェクトを破棄したいので、
Rigidbodyを追加してTriggerEnterイベントを取得できるようにしました。

②について
コライダーは、設定によって下記 3つに区別されます。

  • Static Collider … コライダーのみ。Rigidbody 無し。
  • Rigidbody Collider … コライダーと Rigidbody 両方有り。
  • Kinematic Rigidbody Collider … コライダーと Is Kinematic を有効にしたRigidbody。

物理エンジンは Static Collider が決して移動したり変更されたりしない前提で最適化されているので
Static Collider を変更するとパフォーマンス低下の原因となります。

Kinematic Rigidbody Collider は Static Collider と動作的には似ていますが、
スクリプトで動かしたり、コライダーの有効/無効を切り替えたりしたいときに使う設定です。

Item はスクリプトで常時回転させるので Kinematic Rigidbody Collider を設定しました。

ねこくん
ねこくん

ステージみたいに動かないものは Static Collider でいいんだね!

参考 コライダー – Unity マニュアル



コメント

タイトルとURLをコピーしました