玉転がしゲーム
(
Roll-a-Ball
)を
つくってみよう
レベル:初級
所要時間:
1
時間
25
分
対応バージョン:
Unity 2018.4.22f1(LTS)+
日本語
パック
簡単な玉転がしゲームを作ってみましょう。Unityでゲームづくりをする上での 基本的な操作や、ゲームオブジェクト、コンポーネント、プレハブ、物理演 算、スクリプトなどの機能を学ぶことができます。 ※Unityのインストール方法は「Unityインターハイブログ」の記事「Unity Hub を使ってUnityをインストールしよう」と「Unityエディターを日本語化しよ う」をご確認ください。
マニュアル改訂:
2020
年
5
月
1
このチュートリアルでつくるゲーム
キーボードのテンキー(↑←→↓)を操作して玉を転がし、アイテム を集めるシンプルな3Dゲームです。 全てのアイテムを集めるとクリア、障害物に当たるとはじめからやり 直しとなります。 2まずは新規のプロジェクトを作成しましょう。
1. Unity Hubからプロジェクト→新規作成を選択し、Unityエディターを
起動します。(複数のバージョンがある場合は、新規作成の右側の▼ ボタンをクリックしてバージョン2018.4.22f1を選択しましょう) 2. テンプレートは3Dを選択し、プロジェクト名に作成するゲーム名を 入力します。今回は"Roll-a-Ball"とします。 3. 作成をクリックしてUnityエディターを起動します。
3
シーンを保存する
Unityエディターが開いたら、まずシーンを保存しましょう。
1. ファイル(File)→別名で保存(New Scene)を選択
2. 保存先はScenesを選択し、SampleSceneが入っている画面でファイ ル名をstage01と入力し、保存をクリック プロジェクトとシーン Unity では、ゲーム全体の構成を「プロジェクト」、ゲームの各部を 構成する独立した各場面や各ステージを「シーン」と呼びます。手 の込んだゲームはタイトル画面やゲーム画面などたくさんのシーン を含み、ときには複数のシーンを 1度に組み合わせることもありま す。
4
ゲームづくりをスタートする前に、このチュートリアルでUI(ユー ザーインターフェース)の位置を分かりやすく説明するためにエディ タのUI表示を統一します。
● エディター画面右上のLayoutを選択し、2x3(2 by 3)を選択 ● ゲーム(Game)タブのFree Aspectを選択し、4:3を選択 ● プロジェクトブラウザの下にあるバーを一番左へずらす
インターフェースの使い方
Unityはこの画面でスクリプト制作以外のほとんどの操作を行います。 各ビューの境目にマウスポインタを合わせると幅や高さを調整できま す。最初はシーンビューを使うことが多いので、広めに調整しておく といいでしょう。 61. シーン(Scene)ビュー シーンビューには制作中のゲーム世界(シーン)が表示され、自由な 位置・角度から眺めることができます。 2. ゲーム(Game)ビュー ゲームビューはゲーム画面です。 ゲームのプレイヤーは基本的にこの 画面を見ながらゲームをプレイします。現在は「Main Camera」に 映っているものが表示されています。 3. ヒエラルキー(Hierarchy)ビュー シーン内に存在するオブジェクトの一覧が表示されます。 編集中の シーン内でオブジェクトをコピー/ペーストしたり、名前をつけて整理 することもできます。 4. プロジェクト(Project)ブラウザ 制作中のプロジェクト(ゲーム全体)に含まれるシーン、スクリプ ト、グラフィックやサウンドなどのデータ、その他のファイルが表示 されます。 5. インスペクター(Inspector)ビュー シーンの中で選択中のオブジェクトが持つ属性を表示・編集するため のビューです。 属性には座標やメッシュといった外見上のものから、 衝突判定や物理制御に関するパラメーターなどもあります。
7
シーンビューの移動方法
シーンビューは最初は青とグレーしか表示されていません。まずは3D キューブを作成してみましょう。 1. ヒエラルキービューの作成(Create)を選択 2. 3Dオブジェクト(3D Object)→キューブ(Cube)を選択 続いて以下の操作を試してみましょう。 操作 動作 右クリックを押しながらドラッグ 視点を回転させる マウスホイール Sceneビューの拡大・縮小 ホイールボタンを押しながらドラッグ Sceneビューの並行移動 オブジェクトを選択してFキー オブジェクトにフォーカスを当てる ヒエラルキービューにあるオブジェク ト名をダブルクリック オブジェクトにフォーカスを当てる オブジェクトを選択してDeleteキー オブジェクトを消す 8まずは地面を作成します。これで、シーン内に地面の役割を持った ゲームオブジェクト(GameObject)が作成されます。 1. ヒエラルキービューの作成を選択 2. 3Dオブジェクト→平面(Plane)を選択
9
GameObject(ゲームオブジェクト)とは? Unityでは、シーン内に配置される全ての要素を「ゲームオブジェク ト」と呼びます。 ゲームオブジェクトには物理オブジェクト、ライ ト(照明)、目に見える3Dメッシュ、 あるいは目に見えないサウン ド、トリガーなど様々な形があります。いずれもUnityによって挙動 が管理され、 任意にスクリプトを割り当てて制御できるという共通 点があります。
地面を並べる
地面の大きさを調整します。大きさを調整するには地面を並べるか、 地面を引き伸ばす方法があります。特に理由はないですが、今回は地 面を並べることとします。 1. ヒエラルキービューでPlaneを選択した状態で右クリックし、複製( Duplicate)をクリックします。 2. シーンビューには2つのPlaneが重なった状態になり、2つ目のPlane (Plane(1))が選択されている状態になります。 3. 画面左上のパネルで移動ツールが選択されていることを確認し、シー ンビューに表示されている赤・青・緑の矢印をドラッグして適当に位 置を動かしましょう。 105. 各オブジェクトの名称を変更しましょう。ヒエラルキービューの オブジェクトを右クリックして名前を変更するか、インスペク タービューから名前の変更を行います。 ● Plane → Ground1 ● Plane(1) → Ground2 ● Plane(2) → Ground3 ● Plane(3) → Ground4
11
4つの地面の座標を設定
座標の管理はインスペクタービューのトランスフォーム(Transform )コンポーネントが行っています。位置(Position)、回転(
Rotation)、拡大/縮小(Scale)で管理します。各Groundの位置を以
下のように設定してみましょう。 ● Ground1 → x:5 y:0 z:-5 ● Ground2 → x:5 y:0 z:5 ● Ground3 → x:-5 y:0 z:-5 ● Ground4 → x:-5 y:0 z:5 数値の入力(位置がおかしいときは) 数値にマイナス(-)を付け忘れていないか確認しましょう。 12
ここまでのデータを保存しておきましょう。 1. 画面上部のメニューからファイルを選択 2. 保存(Save Scene)を選択 シーンはこまめに保存 UnityやPCがシャットダウンしてしまうと作業したデータが消えてし まいます。シーンはこまめに保存しましょう。 Ctrl(Command)+Sキーを押すと、簡単に保存ができます。変更 を加えたらCtrl(Command)+Sキーで保存するクセをつけておくと よいでしょう。 13
地面に色を塗る
Unityでモデルに色を塗る方法は2つあります。モデルの表面にテクス チャを設定するか、モデル全体の色や質感を設定することです。 今回 はモデル全体の色をマテリアル(Material)ファイルを使って設定し ます。マテリアル(
Material)ファイルを作
成する
1. プロジェクトブラウザの作成(Create)を選択 2. マテリアル(Material)を選択 3. 作成されたNew Materialの名前をGroundMaterialに変更14
1. 先ほど作成したGroundMaterialを選択
2. アルベド(Albedo)の左の二重丸(◎)を選択し、Default Checker を選択 3. アルベドの右側の枠をクリックして色を設定(好きな色を設定し ましょう)
地面にマテリアル(
Material)を設定
作成したマテリアルを使って地面に色を塗ります。 GroundMaterialを選択し、ヒエラルキービューのGround1、Ground2、 Ground3、Ground4へドラッグ&ドロップします。 またはシーンビューのGround1~4オブジェクトにドラッグ&ドロップし ます。 15壁の作成
四方を壁で囲うステージを作成しましょう。壁はボールがGroundの外 へ逃げることを防ぐ役割を持っています。 1. ヒエラルキービューの作成を選択 2. 3Dオブジェクト→キューブを選択 3. 作成したCubeの名前をWallに変更 16地面と同じように壁の色も設定しましょう。 1. プロジェクトブラウザの作成を選択 2. マテリアルを選択 3. 名前をWallMaterialに変更 4. WallMaterialを選択し、アルベドの色を設定(赤や黄色など、危険色 に設定しましょう) 5. WallMaterialをドラッグ&ドロップしてWallオブジェクトの色を変更
17
壁の配置
壁のサイズを変更しましょう。今回はサイズを引き伸ばす方法を選択 します。左上のパネルでスケールモードを選択してください。そして オブジェクトを選択し、引き延ばしたい方向に伸びているブロックを ドラッグします。 18数値を入力して調整します。Wallを選択した状態で、インスペクター ビューの位置(Position)と拡大/縮小(Scale)に以下の数値を入力 してください。 ● 位置(Position) → x:-0.5 y:0.5 z:-9.5 ● 拡大/縮小(Scale)→ x:19 y:1 z:1 四方を囲むようにつくるので、同じものをあと3個つくります。ヒエ ラルキービューでWallを右クリックして複製を選択し、名前をWall 1 19
に変更します。そして同じようにインスペクタービューで位置と拡大/ 縮小の数値を入力します。 ● 位置(Position) → x:0.5 y:0.5 z:9.5 ● 拡大/縮小(Scale) → x:19 y:1 z:1 Vキーを押しながらモデルを頂点スナップ移動 モデルを選択した状態で、Vキーを押しながらモデルの頂点をクリッ クすると頂点スナップ移動ができます。他モデルの頂点に吸い付く ように移動できる便利なテクニックです。 20
オブジェクトの回転
あと2つ壁をつくります。残りの壁を制作するには2つの方法がありま す。Wallの複製を90度傾けるか、Wallの拡大/縮小(Scale)を【x:1,
y:1, z:19】と異なる方向へ伸ばして作成するかです。今回はWallの複 製を90度傾ける方法について紹介します。 1. ヒエラルキービュー上でWallを右クリックし複製して、名前をWall 2に変更 2. わかりやすいよう、オブジェクトの位置を少しずらす 3. 画面左上のパネルから回転ツールを選択 4. オブジェクトの周囲の球状の枠をドラッグして回転させる 45度ずつ回転 Ctrl(Command)キーを押しながらドラッグすると45度ずつ回転させ ることができます。 21
このようにマウス操作でもオブジェクトを回転させることができます が、今回はインスペクタービューで数値を入力して調整します。Wall 2を選択した状態で、インスペクタービューの位置(Position)と回転 (Rotation)に以下の数値を入力してください。 ● 位置(Position) → x:-9.5 y:0.5 z:0.5 ● 回転(Rotation) → x:0 y:90 z:0 22
残る壁は1つです。Wall 2を複製、名前を変更してWall 3を作成しま しょう。そして位置を調整します。 ● 位置(Position) → x:9.5 y:0.5 z:-0.5 これでステージの地面と壁は完成です! 23
オブジェクトの整理
プロジェクトブラウザやヒエラルキービューにオブジェクトが増えて くると全てを管理するのが面倒になります。フォルダーや空(から) のオブジェクトを使用して整理しましょう。フォルダでマテリアルの整理
マテリアルを1つのフォルダーに格納してまとめます。 1. プロジェクトブラウザの作成を選択 2. フォルダー(Folder)を選択 3. 作成したNew Folderの名前をMaterialに変更 4. GroundMaterialとWallMaterialをMaterialフォルダーへドラッグ&ド ロップ空のオブジェクトで地面と壁の整理
ヒエラルキービューのGroundとWallを空(から)のオブジェクトにま とめます。 1. ヒエラルキービューの作成を選択 2. 空のオブジェクトを作成(Create empty)を選択 3. 作成したGameObjectの名前をStageへ変更 4. WallとGroundを選択し、Stageオブジェクトへドラッグ&ドロップ 24まとめて選択 Ctrl(Command)キーやShiftキーを押しながら選択すると複数のオブ ジェクトやファイルを同時に選択できます。 25
プレイヤー(玉)の作成
プレイヤーとなる玉を作成します。 1. ヒエラルキービューの作成を選択 2. 3Dオブジェクト → スフィア(Sphere)を選択 3. 名前をPlayerに変更 4. インスペクタービューで位置の数値を入力 ● 位置 → x:0 y:1.5 z:0コンポーネントの追加
Playerへコンポーネントを追加しましょう。Playerを選択した状態で インスペクタービューのコンポーネントを追加(Add Component)を 1. シーンビューまたはヒエラルキービューでPlayerを選択 2. インスペクタービューでコンポーネントを追加(Add Component) を選択 3. 物理(Physics)→ リジッドボディ(Rigidbody)を選択 26
ゲームを再生する
ゲーム再生ボタンをクリックし、ゲームの挙動を確認してみましょ う。 Playerに追加したリジッドボディ(物理演算)の機能が働き、オブ ジェクトは地面に落下します。 27正しく動作を確認できたら再びゲーム再生ボタンをクリックし、ゲー ムの再生を終了します。 作業をするときはゲームの再生を終了すること ゲーム再生中に行った作業は、再生が終了するとリセットされます。 作業をするときは必ずゲームの再生を終了してから行うようにしま しょう。
28
の追加
プレイヤー(玉)を転がすゲームにするには、キー入力を受けPlayer オブジェクトを転がす機能が必要です。 この機能はC#(シーシャー プ)スクリプトを書いてつくります。 1. シーンビューまたはヒエラルキービューでPlayerを選択 2. インスペクタービューでコンポーネントを追加を選択 3. 新しいスクリプト(New Script)を選択 4. 名前(Name)にPlayerControllerと入力5. 作成して追加(Create And Add)を選択
これでPlayerオブジェクトに「何も機能を持たないコンポーネント」 が追加されました。 29
この作業で、プロジェクトブラウザのAssetsフォルダーに PlayerControllerが作成されます。これが今回作成した新しいスクリプ トです。 まずはマテリアルと同じようにScriptフォルダを作成し、ドラッグ& ドロップで移動させましょう。 1. プロジェクトブラウザの作成 → フォルダーを選択 2. フォルダー名をScriptに変更 3. PlayerControllerを選択し、Scriptへドラッグ&ドロップ
スクリプトの編集
PlayerControllerをダブルクリックしましょう。通常はVisual Studioが 起動し、スクリプトの編集画面が表示されます。 まずはサンプルコードとして提供されているコードを削除し、クラス 定義のみにします。 using System.Collections; using System.Collections.Generic; using UnityEngine;public class PlayerController : MonoBehaviour {
}
分解すると、以下の通りになりそうです。 1. 毎フレーム、キー入力を受け付ける 2. キー入力がされたらプレイヤーのリジッドボディ(Rigidbody)に力 を加える スクリプト(コード)の記述 このマニュアルではC#スクリプトについて説明もしていますが、最初 は説明の意味がわからないと思います。まずは無理に意味を理解しよ うとせず、書かれているコードを全く同じように記述しましょう。
31
入力機能の追加
まずは「毎フレーム入力を受け付ける」部分をスクリプトで記述しま す。Unityのスクリプトは、特定のメソッドを定義すると自動的にメ ソッドを特定のタイミングで呼び出します。 例えば、クラス内に void Update() { } と記述すると、{}の内側に記述した処理を毎フレーム更新時に呼び出 します。 void FixedUpdate() { } と記述すると、{}の内側に記述した処理を物理演算でキャラクターが 動く度に呼び出します。 今回は物理演算を使用するので、FixedUpdate内に処理を記述しま す。コードを以下のように変更します。 using System.Collections; using System.Collections.Generic; using UnityEngine;public class PlayerController : MonoBehaviour { void FixedUpdate () { } } 32
次に入力をFixedUpdate内で取得します。 以下のコードを記述する と、xとzの中にキーボード入力(Horizontal=↑↓、Vertical=←→) が代入されます。 using System.Collections; using System.Collections.Generic; using UnityEngine;
public class PlayerController : MonoBehaviour { void FixedUpdate () { // 入力をxとzに代入 float x = Input.GetAxis("Horizontal"); float z = Input.GetAxis("Vertical"); } } スクリプトを編集したら保存しましょう。ファイル(File) → 保存(Save) を選択します。Ctrl(Command)+Sキーでも保存ができます。 33
// によるコメントアウト C#スクリプト内で // を記述すると、以降の内容は処理されなくなりま す。日本語でスクリプトの内容や動作を説明したり、メモ書きとして 使用します。本マニュアルでは見やすくするために過去のコメントを 省略しています。
34
物理演算機能の追加
取得したキー入力を元にrigidbodyコンポーネントに力を加えます。 同 一オブジェクトのコンポーネントを取得するにはGetComponentを使 用します。今回はリジッドボディ(Rigidbody)を取得するので、「 GetComponent<Rigidbody>()」と記述します。 using System.Collections; using System.Collections.Generic; using UnityEngine;public class PlayerController : MonoBehaviour {
void FixedUpdate () {
float x = Input.GetAxis("Horizontal"); float z = Input.GetAxis("Vertical");
// 同一のGameObjectが持つRigidbodyコンポーネントを取得 Rigidbody rigidbody = GetComponent<Rigidbody>();
} } 取得したrigidbodyに入力の力を加えます。力を加えるにはPublic関数 のAddForceを使います。 35
using System.Collections;
using System.Collections.Generic; using UnityEngine;
public class PlayerController : MonoBehaviour {
void FixedUpdate () {
float x = Input.GetAxis("Horizontal"); float z = Input.GetAxis("Vertical");
Rigidbody rigidbody = GetComponent<Rigidbody>();
// rigidbodyのx軸(横)とz軸(奥)に力を加える rigidbody.AddForce(x, 0, z); } } これで機能はひと通り作成しました。それではゲームを再生してみま しょう。 テンキー(↑↓←→)を入力すると玉(Player)が非常にゆっくり動 きます。 36
using System.Collections;
using System.Collections.Generic; using UnityEngine;
public class PlayerController : MonoBehaviour {
void FixedUpdate () {
float x = Input.GetAxis("Horizontal"); float z = Input.GetAxis("Vertical");
Rigidbody rigidbody = GetComponent<Rigidbody>();
// xとzに10をかけて押す力をアップ rigidbody.AddForce(x * 10, 0, z * 10); } } 再びゲームを再生してみるとスムーズになったはずです。しかしゲー ムバランスに直結する項目なので、じっくり調整したいですね。毎回 スクリプトを開いて調整するのは大変なので、この値をインスペク タービューからサクっと調整できるようにしましょう。 まずはPlayerControllerクラスにspeed変数を追加します。 その後、 speed変数をxとzに掛けるよう変更します。 37
using System.Collections;
using System.Collections.Generic; using UnityEngine;
public class PlayerController : MonoBehaviour {
// speedを制御する
public float speed = 10;
void FixedUpdate () {
float x = Input.GetAxis("Horizontal"); float z = Input.GetAxis("Vertical");
Rigidbody rigidbody = GetComponent<Rigidbody>(); // xとzにspeedを掛ける
rigidbody.AddForce(x * speed, 0, z * speed); }
}
Playerを選択してインスペクタービューのPlayer Controller (Script)を 見ると速度(speed)欄が追加され、数値を調整できるようになりま した。 初期値は10となっていますが、自由に数値を変えてゲームを再生して みましょう。 38
Playerの動きに合わせてカメラを動かしましょう。最も簡単な方法 は、Playerを親オブジェクト、MainCameraを子オブジェクトに設定す ることです。親子関係にあるオブジェクトは、どちらかが動けばもう 片方も同じ動きをします。 1. ヒエラルキービューのMainCameraを選択 2. MainCameraをヒエラルキービューのPlayerへドラッグ&ドロップ ゲームを再生せずPlayerオブジェクトを動かしてみましょう。カメラ はプレイヤーを追随して移動しています。 39
ではゲームを再生してみてください。ゲームビューを見ると世界がグ ルングルン回っています。 Player自体が転がって移動しているため、親子関係にあるカメラも転 がってしまうためです。 これを解決するにはPlayerが転がらないよう に移動するか、カメラがプレイヤーを追跡するコンポーネントを作る かです。今回はカメラがプレイヤーを追跡するコンポーネントを作り ます。 40
プレイヤーを追跡するコンポーネント
の作成
カメラがプレイヤーを追跡するコンポーネント(新しいスクリプト) を作成します。 機能を分解してみましょう。 1. Playerの位置を取得する 2. 毎フレームPlayerの位置へ座標を調整する まずはFollowPlayerコンポーネントを作成し、MainCameraへ追加しま す。 1. ヒエラルキービューでMainCameraを選択 2. インスペクタービューでコンポーネントの追加を選択 3. 新しいスクリプトを選択し、名前をFollowPlayerにして作成して追加 を選択 4. プロジェクトブラウザでAssetsフォルダー内に作成された FollowPlayerをScriptフォルダーへ移動 41
Scriptフォルダーに入れたFollowPlayerをダブルクリックし、Visual
Studioを起動します。
カメラがプレイヤーを追跡する方法はいくつか考えられるのですが、 今回はシーン上にあるPlayerオブジェクトへの参照を事前に設定し、 参照を元にオブジェクトの座標を取得する方法を選択します。 まずはコードの設定です。 先ほどと同じようにpublicで宣言します が、今度はTransformの変数を定義します。 これはTransformのコン ポーネントを持つオブジェクトを登録するためです。 using System.Collections; using System.Collections.Generic; using UnityEngine;
public class FollowPlayer : MonoBehaviour {
public Transform target; // ターゲットへの参照
void Update () { // 自分の座標にtargetの座標を代入する GetComponent<Transform>().position = target.position; } } コードを記述したらUnityエディターへ戻り、MainCameraを選択して インスペクタービューのコンポーネント一覧を確認しましょう。 FollowCameraコンポーネントにTargetの項目が追加されていることが わかります。 この項目へ登録したいオブジェクト(Player)をドラッグ&ドロップ します。 43
さて再生してみましょう。するとカメラの位置は変更されましたが、 プレイヤー(玉)が映っていません。MainCameraとPlayerが同じ座標 にいるため、主観視点になってしまっています。
Offsetを設定する
これはこれで面白いのですが、遊びやすくするにはプレイヤー(玉) が見えるようにカメラの位置を設定したいですね。 そこでゲーム再生時にあるカメラとプレイヤー距離を維持する機能 (スクリプト)を追加します。 ゲームを再生した時にPlayerと MainCameraの相対距離を求めて保持しておき、毎フレーム、カメラ の位置をPlayerの位置との相対距離で設定する事で実現します。 44y:1.5, z:0 にあることを確認しましょう。そしてMainCameraの位置 を以下のとおりにします。 ● 位置(Position) → x:0 y:9 z:-5 ● 回転(Rotation) → x:60 y:0 z:0 次にFollowPlayerコンポーネント(スクリプト)のコードを変更しま す。 45
Startはコンポーネントの起動時に1度だけ呼び出されるメソッドで す。ここでoffsetへ相対距離を取得しておきます。相対距離を使用し て、常に一定の距離を離してPlayerを追跡するようにします。 using System.Collections; using System.Collections.Generic; using UnityEngine;
public class FollowPlayer : MonoBehaviour {
public Transform target; // ターゲットへの参照
private Vector3 offset; // 相対座標 void Start () { //自分自身とtargetとの相対距離を求める offset = GetComponent<Transform>().position - target.position; } void Update () { // 自分自身の座標に、targetの座標に相対座標を足した値を 設定する GetComponent<Transform>().position = target.position + offset; } } 46
ゲームを再生してみてください。プレイヤーはステージ内を自由に走 り回り、カメラもちょうどいい位置で追跡していますね! ここまでで全体の約60%です。残りはあと40%なので一度休憩を入れ ましょう。おっと、次の作業に移る前にゲーム再生を終了することを 忘れずに。 47
Itemオブジェクトの追加
さあ、次はプレイヤーが集めるItemオブジェクトを作ります。まず Itemの元となる3Dモデルを作成します。 1. ヒエラルキービューの作成を選択 2. 3Dオブジェクト → カプセル(Capsule)を選択 3. 名前をItemに変更 作成したカプセル(Item)は少し大きすぎるので、大きさと位置を調 整します。 ● 位置(Position) → x:0 y:1 z:0 ● 拡大/縮小(Scale) → x:0.5 y:0.5 z:0.5 48き出す
この作成したItemはこのあと複数つくることになります。1個ずつ色 や大きさを調整するのは大変ですね。そのためにオブジェクト構成情 報をprefab(プレハブ)として書き出します。 まずは今回も専用のPrefabフォルダーを作成してそこに整理しましょ う。 1. プロジェクトブラウザでAssetsを選択し作成 → フォルダーを選択 2. 名前をPrefabに変更 続いてItemオブジェクトをPrefabとして書き出します。 1. ヒエラルキービューのItemを選択 2. ItemをプロジェクトブラウザのPrefabフォルダーへドラッグ&ド ロップ 49
青いアイコンのPrefabオブジェクトができます。
PrefabのItemをシーンへ配置します。 1. プロジェクトブラウザのPrefabフォルダーのItemを選択 2. シーンビューへドラッグ&ドロップ 6個のPrefabを円形に配置してみましょう。ヒエラルキービューにも Item (1)~Item (6)が追加されていることがわかります。 最初にセットアップしたItemは、オブジェクトを選択してDeleteキー で消しておきましょう。
アイテムの色を設定する
Item(1)の色を設定しましょう。 1. プロジェクトブラウザの作成を選択 2. マテリアルを選択 3. 名前をItemMaterialに変更 4. ItemMaterialを選択し、アルベドの色を設定(好きな色を設定しま しょう) 5. ItemMaterialをドラッグ&ドロップしてItem(1)オブジェクトの色 を変更 51
Prefabの更新
Item(1)を使ってマテリアルを設定しました。この調整を他のItem(2) ~Item(6)にも適用します。 1. ヒエラルキービューでItem(1)を選択 2. インスペクタービューでオーバーライド(Overrides)を選択し、す べてを適用する(Apply All)を選択 同じPrefabであるItem(2)~Item(6)にもマテリアルが適用されまし た! 52Itemに、Playerが接触したときの判定をコンポーネントに追加しま す。 1. ヒエラルキービューでItem(1)を選択 2. インスペクタービューでコンポーネントの追加→ 新しいスクリプト を選択 3. 名前をItemScriptに設定し作成して追加を選択 4. プロジェクトブラウザのAssetsフォルダー内に作成されたItemScript をScriptフォルダーにドラッグ&ドロップ 5. ItemScriptをダブルクリックして開く 接触判定の関数は2種類あります。 ● OnTriggerEnter :物理的な反射を持たないTriggerとの接触判定 ● OnCollisionEnter :物理的な反射を持つColliderとの接触判定 プレイヤーとアイテムが接触したときにスルッと抜けて欲しいので OnTriggerEnterを使って実装します。 using System.Collections; using System.Collections.Generic; using UnityEngine;
public class ItemScript : MonoBehaviour {
// トリガーとの接触時に呼ばれるコールバック
void OnTriggerEnter (Collider hit)
{ } }
Itemの接触判定をTriggerに変更
判定方式をTriggerにしたため、接触判定もTriggerに設定する必要があ ります。 Item (1)のColliderをTriggerに設定します。 1. ヒエラルキービューのItem (1)を選択 2. インスペクタービューのカプセルコライダー(CapsuleCollider)コ ンポーネントのトリガーにする(Is Trigger)にチェックを入れる54
先ほどの処理で、Item(1)があらゆるTriggerとの接触判定を行うことが できるようになりました。しかし今回、Item(1)と接触判定を持つのは Playerのみとしたいです。 いくつかの方法があるのですが、今回はシンプルで汎用的なタグを確 認する方法を使います。OnTriggerEnterの引数であるhitには、接触対 象の情報が含まれます。この接触対象のタグを調べ、Playerならば特 別な処理を行うようにItemScriptを以下のように修正します。 using System.Collections; using System.Collections.Generic; using UnityEngine;
public class ItemScript : MonoBehaviour {
// トリガーとの接触時に呼ばれるコールバック
void OnTriggerEnter (Collider hit)
{ // 接触対象はPlayerタグですか? if (hit.CompareTag ("Player")) { // 何らかの処理 } } }
55
Playerにタグを設定する
Playerオブジェクトにタグを設定してみましょう。 1. ヒエラルキービューでPlayerを選択 2. インスペクタービューのタグ(Tag)をPlayerに設定56
プレイヤーがアイテムに接触したらアイテムが消えるように設定しま す。消える=シーンからの削除にはDestroyメソッドを使用します。 using System.Collections; using System.Collections.Generic; using UnityEngine;
public class ItemScript : MonoBehaviour {
// トリガーとの接触時に呼ばれるコールバック
void OnTriggerEnter (Collider hit)
{
// 接触対象はPlayerタグですか?
if (hit.CompareTag ("Player")) {
// このコンポーネントを持つGameObjectを破棄する Destroy(gameObject); } } }
57
Prefabの更新
ここまでItem(1)を使って調整してきました。先ほどと同じように、こ の調整を他のItem(2)~Item(6)にも適用します。 1. ヒエラルキービューでItem(1)を選択 2. インスペクタービューでオーバーライド(Overrides)を選択し、 すべてを適用する(Apply All)を選択 ゲームを再生してみましょう。アイテムに接触するとアイテムが消える ことがわかります。ゲームらしくなってきましたね! 58ヒエラルキービューのItem(1)~Item(6)を整理しましょう。 1. ヒエラルキービューで作成→空のオブジェクトを作成を選択 2. 名前をItemsに変更 3. Item(1)~Item(6)をすべて選択し、Itemsへドラッグ&ドロップ 59
「残りのアイテム数」を表示する
UIの
作成
UI(ユーザーインターフェース)は、主にゲーム中の画面に表示され る数字や文字を指します。ここでは画面左下に残りのアイテム数を表 示するUIを作成します。60
まずはUIを表示するCanvasを用意します。 1. ヒエラルキービューの作成→UI→キャンバス(Canvas)を選択 シーンビューでは巨大なキャンバスオブジェクトが確認できます。UI は他の3Dモデルと違い、ゲーム中の画面の手前に表示されるので、巨 大であることは無視してください。 61
キャンバスのサイズを設定します。
1. ヒエラルキービューでCanvasを選択
2. インスペクタービューでキャンバススケーラ(CanvasScaler)のUI
スケールモード(UI Scale Mode)を画面サイズに拡大(Scale With Screen Size)に設定
UIに表示するテキスト(文字や数字)を設定します。 1. ヒエラルキービューの作成→UI→テキスト(Text)を選択 2. 名前をScoreLabelに変更 ※作成したテキスト(Text)は自動的にCanvasの子オブジェクトとなり ます。 現在はデフォルトのNew Textというテキストが表示されています。ま ずは表示位置を左下へ移動し、フォントの大きさを調整します。 1. ヒエラルキービューでCanvas→ScoreLabelを選択 2. 短形トランスフォーム(RectTransform)の値を以下のように設定 ● 位置X(PosX):-230 ● 位置Y(PosY):-230 ● 位置Z(PosZ):0 ● 幅(Width):300 ● 高さ(Height):100 3. テキスト(Text)コンポーネントのテキスト(Text)欄に0と記入 し、フォントサイズ(Font Size)を60に設定 63
次に、シーン内の残りのアイテムの数を、先ほど作成したScoreLabel に通知して表示する仕組みを作成します。 この機能を実装する方法は無数にありますが、今回は一番簡単な GameControllerに管理させる方法を使います。アイテム数のような ゲーム全体の進行に関する機能はGameControllerが持つのが望ましい です。このGameControllerがシーン内のアイテム(Item)の残数を数 え、変更があればScoreLabelに通知するという仕組みです。 ではGameControllerを作成していきましょう。 1. ヒエラルキービューの作成→空のゲームオブジェクトを選択 2. 名前をGameControllerに変更 3. インスペクタービューでタグをGameControllerに設定
65
タグの設定
今回はItem(1)~Item(6)に新しくItemタグを設定し、このタグを持つ オブジェクトの数を計測する方法を使用します。
1. 画面上部のメニューの編集(Edit) → ProjectSettings → Tags And Layersを選択
2. タグ(Tag)の左にある▼ボタンを選択し、右側にある+ボタンを選
択
3. New Tag NameにItemと入力してSaveを選択
66
る
作成したItemタグをItem(1)~Item(6)に設定しましょう。先ほどの作 業で一覧にItemタグが追加されています。 1. ヒエラルキービューでItem(1)を選択 2. インスペクタービューでタグをItemに設定 3. オーバーライド→すべてを適用するを選択 オーバーライド→すべてを適用するを行うことで、同じPrefabである Item(2)~Item(6)すべてに設定が適用されます。67
Itemをカウントする機能を追加
GameControllerにItemのタグを持つオブジェクトをカウントする機能 を追加します。GameControllerオブジェクトにGameControllerコン ポーネントを作成して追加しましょう。 1. ヒエラルキービューでGameControllerを選択 2. インスペクタービューでコンポーネントを追加を選択 3. 新しいスクリプトを選択し、名前をGameControllerにして作成して 追加を選択 4. プロジェクトブラウザのAssetsフォルダー内に作成された GameControllerをScriptフォルダーに移動 5. GameControllerをダブルクリックして開く GameControllerに以下のようにコードを記述します。 using System.Collections; using System.Collections.Generic; using UnityEngine;public class GameController : MonoBehaviour {
public void Update ()
{
int count = GameObject.FindGameObjectsWithTag ("Item").Length; }
}
残りのアイテム数を、UIのScoreLabelに表示するようにします。 まずはGameControllerからTextコンポーネントへアクセスする方法と して、Textコンポーネントへの参照を設定する方法を利用します。 まずは参照に使用するコードを作成します。 using System.Collections; using System.Collections.Generic; using UnityEngine;
public class GameController : MonoBehaviour {
public UnityEngine.UI.Text scoreLabel;
public void Update ()
{
int count = GameObject.FindGameObjectsWithTag ("Item").Length; }
}
次に取得したItem数をtextに代入します。 using System.Collections;
using System.Collections.Generic; using UnityEngine;
public class GameController : MonoBehaviour {
public UnityEngine.UI.Text scoreLabel; public void Update ()
{
int count = GameObject.FindGameObjectsWithTag ("Item").Length; scoreLabel.text = count.ToString ();
} }
け
作成したGameControllerとScoreLabelを紐付けます。 1. ヒエラルキービューでGameControllerを選択 2. ScoreLabelをScoreLabelの欄へドラッグ&ドロップ ゲームを再生してみてください。 画面左下に残りのアイテム数が表示 され、プレイヤーがアイテムを取得する度にアイテム数が減ることが わかりますね! 71
クリア時の
UIを作成
次は、アイテム数と同じUIテキストの機能を使ってクリア時(アイテ ムをすべて取った時)の表示を作成します。 1. ヒエラルキービューの作成→UI→テキストを選択 2. 名前をWinnerLabelに変更 72続いてWinnerLabelの内容を設定します。 1. ヒエラルキービューでWinnerLabelを選択 2. インスペクタービューで短形トランスフォームを以下の値に設定 ● 位置X:0 ● 位置Y:0 ● 位置Z:0 ● 幅:300 ● 高さ:100 3. テキスト欄にYOU WINと入力 4. フォントサイズを60に設定 73
クリア条件の設定
続いてGameControllerに少し手を加えてクリア条件を設定します。 今回のゲームではアイテムを全て回収する=残りのアイテムが0にな ることが勝利条件です。シーン内にItemタグを持つオブジェクトが見 つからなかったら(全てなくなったら)勝利とします。 1. プロジェクトブラウザでGameControllerをダブルクリックして開 く 2. コードを以下のように修正 using System.Collections; using System.Collections.Generic; using UnityEngine;public class GameController : MonoBehaviour {
public UnityEngine.UI.Text scoreLabel; public void Update ()
{
int count = GameObject.FindGameObjectsWithTag ("Item").Length; scoreLabel.text = count.ToString (); if (count == 0) { // クリア時の処理 } } }
74
参照を設定
最後にクリア時に初めて「YOU WIN」の文字が表示されるようにしま す。今回もWinner Labelへの参照が必要ですが、今までと同様にエ ディター側で設定します。 GameControllerを以下のように修正します。 using System.Collections; using System.Collections.Generic; using UnityEngine;public class GameController : MonoBehaviour {
public UnityEngine.UI.Text scoreLabel; public GameObject winnerLabelObject;
public void Update ()
{
int count = GameObject.FindGameObjectsWithTag ("Item").Length; scoreLabel.text = count.ToString (); if (count == 0) { // クリア時の処理 } } } GameControllerからWinnerLabelへの参照を設定します。 1. ヒエラルキービューでGameControllerを選択 2. ヒエラルキービューのWinnerLabelをインスペクタービューの
GameControllerコンポーネントのWinner Label Objectへドラッグ&
ドロップ
ここでゲームを再生してみましょう。YOU WINの表示が最初から出て しまっていますね。
クリア条件を満たすまで、YOU WINを非表示にします。 Unityで描画されているものを非表示にする方法はいくつかあります が、今回はオブジェクトを非アクティブにする事で非表示にします。 1. ヒエラルキービューでWinnerLabelを選択 2. インスペクタービューでオブジェクトのチェックを外す これでシーンビューやゲームビューからもYOU WINの表示が消えまし た。 77
クリア時に「
YOU WIN」と表示する
クリア時に非アクティブの「Winner Label」をアクティブにすること で、ゲームクリア時にYOU WINと表示します。 using System.Collections; using System.Collections.Generic; using UnityEngine;public class GameController : MonoBehaviour {
public UnityEngine.UI.Text scoreLabel; public GameObject winnerLabelObject; public void Update ()
{
int count = GameObject.FindGameObjectsWithTag ("Item").Length; scoreLabel.text = count.ToString (); if (count == 0) { // オブジェクトをアクティブにする winnerLabelObject.SetActive (true); } } }
78
ゲームを再生してみましょう。プレイヤーがすべてのアイテムを取 り、アイテム数が0になるとYOU WINの文字が表示されるようになり ましたね! しかし、これだけではただアイテムを集めるだけの作業になってし まっていて面白みに欠けます。最後の仕上げとして、接触してはいけ ない障害物を作成しましょう。完成まであとひと息です! 79
障害物の作成
まずは障害物の3Dモデルを作成します。DangerWallプレハブの作成
1. ヒエラルキービューの作成→3Dオブジェクト→キューブを選択 2. 名前をDangerWallに変更 3. ヒエラルキービューのDangerWallをプロジェクトブラウザのPrefab フォルダーにドラッグ&ドロップしてPrefabのDangerWallを作成80
DangerWallは接触してはいけない危険な壁です。より危険度が高く見 えるよう「光る壁」としてマテリアルを設定します。 1. プロジェクトブラウザで作成→マテリアルを選択 2. 名前をDangerWallMaterialに変更 3. DangerWallMaterialをMaterialフォルダーに移動 4. インスペクタービューで以下を設定 ● アルベド(Albedo):赤や黄色など危険色(地面や壁とは別の色 にする) ● 放出(Emission):チェックを入れ、色をアルベドと同様の色を 設定。強度(Intensity)を1.3に設定 81
5. DangerWallMaterialをヒエラルキービューのDangerWall(またはシー ンビューのDangerWallオブジェクト)へドラッグ&ドロップ 6. ヒエラルキービューのDangerWallを選択し、インスペクタービュー のオーバーライド→すべてを適用するを選択 82
DangerWallの配置
DangerWallのサイズと位置を調整しましょう。 1. ヒエラルキービューのDangerWallを選択 2. インスペクタービューのトランスフォームコンポーネントを以下 のように設定 ● 位置(Position) :X:4 Y:0.5 Z:3 ● 回転(Rotation) :X:0 Y:0 Z:0 ● 拡大/縮小(Scale) :X:10 Y:1 Z:1 このとき、調整したDangerWallがItemと重なってしまうとクリアでき なくなります。もし重なる場合はItemの位置を少しずらしましょう。 84DangerWallを複製し、位置・回転・拡大/縮小の数値を調整してステー ジ内に配置してみましょう。この部分は好きなように複製、配置して 構いません。ここでは例として以下のように設定してみます。 1. ヒエラルキービューのDangerWallを選択し、右クリックして複製 を選択 2. さらにもう一度複製を選択し、DangerWallオブジェクトを合計3個 にする 3. DangerWallオブジェクトの名前をDangerWall 1、DangerWall 2、 DangerWall 3に変更 4. それぞれの位置・回転・拡大/縮小の数値を調整 DangerWall 1
* position (x:4, y:0.5, z:3) rotation (x:0, y:0, z:0) scale(x:10, y:1, z:1) DangerWall 2
* position (x:4, y:0.5, z:-4) rotation (x:0, y:0, z:0) scale(x:10, y:1, z:1) DangerWall 3
* position (x:-5, y:0.5, z:4) rotation (x:0, y:90, z:0) scale(x:10, y:1, z:1) ゲームを再生して、DangerWallとItemが重なっていないことを確認し ましょう。この時点ではDangerWallはただの壁で、接触しても何も起 こりません。 85
DangerWallの整理
DangerWallオブジェクトが増えてきましたね。Item同様、空のゲーム オブジェクトを作って整理しましょう。 1. ヒエラルキービューの作成→空のオブジェクトを作成を選択 2. 名前をDangerWallsに変更 3. DangerWallオブジェクトを全てDangerWallsへドラッグ&ドロップDangerWallとStageの静的(static)
化
先ほどマテリアルで設定した放出(Emission)による発光エフェクト は、発光する側のオブジェクトと光を受けるオブジェクトの両方を静 的(static)に設定することで効果を発揮します。 1. DangerWallsを選択した状態でインスペクタービューの静的( static)にチェックを入れる2. 表示されるダイアログでYes, change childrenを選択
3. Stagesを選択した状態でインスペクタービューの静的(static)に
チェックを入れる
4. 表示されるダイアログでYes, change childrenを選択
ライティング(
Lighting)設定とマテ
リアルの調整
オブジェクトを静的に設定することで放出の発光エフェクトが反映さ れるようになりました。この時、発光エフェクト等の情報が裏で処 理・保存されています。この処理のことをベイク(Bake、焼き付け) と呼びます。 地面の色が濃いとベイクによる変化がわかりにくいかもしれません。 プロジェクトブラウザでGroundMaterialを選択し、色を調整してみま しょう。 87自動ベイクと手動ベイク
見栄えは良くなりましたが、ベイクはPCに負荷がかかります。また、 ベイク途中でシーンを再生してしまうと表示がおかしくなることがあ ります。 オブジェクトを動かしたり、マテリアルを調整するたびに自動的にベ イクがかかるのを避けるためには、以下の手順でライティングの自動 生成をオフにして手動でベイクしましょう。 1. 画面上部のメニューからウインドウ(Window)→レンダリング(Rendering)→ライティング設定(Lighting Settings)を選択
2. 下方にある自動生成(Auto Generate)のチェックをオフにする
3. 自動生成の右にあるライティングの生成(Generate Lighting)
を選択
太陽光の輝度を下げる
DangerWallはマテリアルの設定で放出(Emission)の強度を1.3にし たため、光っているのですが太陽光の強度(Intensity)が高く、少し 分かり難いです。太陽光の強度を下げて調整してみましょう。 1. ヒエラルキービューのDirectionalLightを選択 2. インスペクタービューでライト(Light)コンポーネントの強度( Intensity)を0.6に設定90
最後に、障害物に当たったらシーンを再起動する機能を作成します。 1. ヒエラルキービューでDangerWall 1を選択 2. インスペクタービューでコンポーネントを追加を選択 3. 新しいスクリプトを選択し、名前をDangerWallScriptに設定して作成 して追加を選択 4. オーバーライド→すべてを適用するを選択 5. DangerWallScriptをScriptフォルダーに移動
91
スクリプトによる判定
DangerWallScriptをダブルクリックして開き、「接触したか」の判定を 受けるコールバックを設定します。 using System.Collections; using System.Collections.Generic; using UnityEngine;public class DangerWallScript : MonoBehaviour {
// オブジェクトと接触した時に呼ばれるコールバック
void OnCollisionEnter (Collision hit)
{ // 何かの処理 } }
92
DangerWallの接触対象がPlayerタグを持つオブジェクトの場合、シー ンを再読込し、ゲームを最初の状態にリセットします。 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement;
public class DangerWallScript : MonoBehaviour {
// オブジェクトと接触した時に呼ばれるコールバック
void OnCollisionEnter (Collision hit)
{
// 接触したオブジェクトのタグが"Player"の場合 if (hit.gameObject.CompareTag ("Player")) {
// 現在のシーン番号を取得
int sceneIndex = SceneManager.GetActiveScene().buildIndex;
// 現在のシーンを再読込する SceneManager.LoadScene(sceneIndex); } } } ゲームを再生してみてください。DangerWallに当たるとゲームがリ セットされてしまうため、精密な操作を要求するゲームになりました ね! 93