Unity匠塾 Vol.2

Tips
Unity
エンジニア
ゲーム
ツール

エンジニア

Unity匠塾 Vol.2

今回は2Dオブジェクトの扱いとゲーム完成に向けて進めていきます。
前回のプロジェクトを基に説明を行っていきますので、「Unity匠塾 Vol.1」をまだお読みでない場合はぜひ読んでみてください。

2Dオブジェクトとは

2Dオブジェクトとは奥行きのない平たいオブジェクトのことです。
例えば横スクロールの2Dゲームではキャラクターや背景など、表示されるもののほとんどが2Dオブジェクトで構成されています。
3Dゲームでは体力バーであったり、スコア表示など、主にUIと呼ばれる部分での表示に使われています。
今回はuGUIを使いながら2Dオブジェクトについて触れていきます。

uGUIとは

uGUIとは、現在Unity標準として搭載されている、2Dに関わるUIの生成や管理を行うツールのことです。
「Unity基礎前編」で3Dオブジェクトを配置した時のように「Hierarchy」ビュー上で右クリックすると表示されるメニューのうち「UI」という項目の中にあるものがuGUIのオブジェクトになります。
こちらもいくつか種類があるのでよく使うものから説明していきます。

Canvasとは

簡単に言うと「Canvas」とは配置するuGUIの親、つまり一番基底のオブジェクトです。
uGUIのオブジェクトを利用する際には、最低でも一つは配置されるオブジェクトとなります。
この「Canvas」配下に置かれたオブジェクトのみが画面上に表示されるため、uGUIを配置する際に一番最初に配置するものになります。
まず最初に「Hierarchy」内で右クリックをして「UI」→「Canvas」と選択し、生成します。
これでuGUIオブジェクトを配置する準備ができました。

uGUIを配置してみよう

次に「Text」オブジェクトを配置していきます。
「Text」オブジェクトは、読んで字の如く画面上に文字や数字を表示するためのオブジェクトです。
ゲーム上でよく使われる箇所として、所持金の表示やゲーム内スコアの表示、キャラクター名の表示などが挙げられます。
ではさっそく配置していきます。
「Canvas」を選択した後右クリックから「UI」→「Text」と選びます。
これで配置できました!

・・・が画面上に大きな変化は見られませんね。
「Scene」ビューでは3Dと2Dの表示を切り替えて確認する必要があります。
理由としては、オブジェクトを配置したりパラメータを変更する時に混合するとややこしくなるためです。

2D切り替えボタンとCanvas枠の説明

ビュー上部にある2Dと書かれたタブをクリックしてみましょう。
これで2Dの表示になりました。
次に「Hierarchy」の「Canvas」オブジェクトをダブルクリックします。
するとだいぶ遠目に小さく「Text」が見えるようになりました。
マウスホイールを回して、ビュー内を拡大していくと「New Text」と書かれた文字が見えるようなるはずです。

また、現在「Scene」ビュー上に表示されている四角形の枠の部分がゲーム画面の境界になります。
この中の右上に「Text」を配置した場合はゲーム画面上でも常に右上に表示されます。
ではさっそく「Text」の値を変更し、ゲーム画面にどのような変化があるのか見てみましょう。

パラメータの設定

「Text」オブジェクトを選択して「Inspector」ビューを確認します。
「Inspector」ビューを見ると、3Dオブジェクトと違い「RectTransform」というコンポーネントと「Text」というコンポーネントがくっついています。
まず「Text」コンポーネント内の「Text」項目を変更していきます。
今回は最終的に作るゲーム内で時間を表示したいので「Text」の項目に「0」と入力します。
次に「Scene」ビューから「Game」ビューに切り替えてみましょう。
すると画面上に「Unity基礎前編」で配置した3Dオブジェクトとともに「0」が表示されています。
また、説明が遅れましたが、この「Game」画面で「Aspest比」(画面の縦横の比率)の変更ができます。
初期値では「FreeAspect」となっており、このビューの大きさを変更すると自動的に変更されてしまうため、今回は「16:9」で設定しましょう。
では「Scene」ビューに戻って「Text」の位置と大きさをを変更していきます。

値変更後のTextのInspector

まず「RectTransform」を「0,70,0」に、「Text」の「FontSize」を「30」に変更します。
また、現状の「Text」の表示領域(Width,Height)ではこのFontSizeは表示できないため、「Height」の値を「50」に変更します。
さらに、「Text」の表示が左上に寄っているので「Text」コンポーネントの「Alignment」を「中央寄せ/中段」変更します。 これできれいに表示することができました。
次に他のuGUIについても簡単に説明していきます。

よく使われるuGUIオブジェクトの説明

・「Image」
画像を設定する際に使用します。
・「Button」
その名の通りボタンを配置します。
ボタンクリック時の挙動を設定できます。

簡単なゲームを作ってみよう

いよいよゲームの制作に移っていきます。
今回作成していくのは「迷路ゲーム」です。

手順として
1.「Sphere」オブジェクトをキャラクターとして動かす
2.「Cube」オブジェクトを壁として配置し、迷路を作る
3.ゴールを配置する
4.ゴール到達までの時間を計測する

上記実装を順に行い、玉をゴールまで早く運ぶことを目標にしたゲームを作成しましょう。

スクリプトを書いてみよう

オブジェクトを制御するためにスクリプトを作成する必要があります。
「スクリプト」とはオブジェクトの移動を制御したり、プレイヤーの入力に応じた挙動の設定など、オブジェクトの振る舞いを記述するものです。
今回は基になるスクリプトを用意したのでダウンロードして確認しながら進めましょう。

ダウンロードしていただくファイルはこちらの3種類です。
Character.cs
Timer.cs
GoalObject.cs

オブジェクトを動かしてみよう

まずは「Sphere」を動かすスクリプトを書いていきます。
シーンを作成した時と同じように「Project」ビューに「Script」フォルダを生成します。
「Project」ビューを右クリックして「Create」→「Folder」と選び、名前を「Script」とします。
「Script」フォルダをダブルクリックし、「Project」ビュー内を右クリック後、
「Create」→「C#Script」と選択してフォルダ名は「Character」としましょう。
作成したスクリプトをダブルクリックするとスクリプトエディタが開きます。
(WindowsであればVisualStadio、MacであればMonoDevelopが開きます。)
(ソフトは違っても行うことは一緒ですので、同じように記述をしていきます。)
ここではダウンロードした「Character.cs」を基に説明していくので、「Character.cs」を確認しながら実装を進めます。

スクリプト内には既に「Start」と「Update」と書かれたものがあります。
「Start」と「Update」にはそれぞれに意味があり、中括弧の中に命令文(やらせたいこと)を記述するのはどちらも同じですが、命令が実行されるタイミングが異なります。
これは関数と呼ばれるものですが、初めのうちは、

・「Start」と書かれた中括弧の中に書くものが初めに一回だけ行われる処理
・「Update」と書かれた中括弧の中に書くものが毎フレーム行われる処理

と覚えましょう。
フレームというものは毎描画時の単位のことであり、よく聞く「60Fps」という単語は「1秒間に60回更新される/描画を行う」という意味になります。
この「Update」内に書かれているプログラムの処理を説明していきます。
Input.GetKeyというものでキーの入力を受けつけています。
"up"(上キー入力)した時に「transform」のポジションを書き換えて、上方向に移動するようになっています。
このスクリプトをオブジェクトに反映していきます。

作成した「Character」スクリプトを「Sphere」オブジェクトにドラッグ&ドロップします。
すると「Inspector」の一番下に「Character」が追加されました。
また、この時に「RigidBody」コンポーネントの「Contraints」から「FreeseRotation」プロパティの「x,y,z」全てにチェックを入れておきましょう。
これで「Sphere」が回転しなくなるため、常に動いて欲しい方向にのみ移動してくれるようになります。
これでシーンを再生してみましょう。
すると方向キー入力に応じて上下左右に移動するようになりました。
ただ、現状だと見づらいためカメラの「Transform」を変更します。
「Hierarchy」の「MainCamera」を選択し、「Inspector」にある「Transform」の「Position」を「0,12,-4」、「Rotation」を「70,0,0」に変更します。

壁オブジェクトの生成

次は迷路の壁の部分を生成していきます。
「Hierarchy」ビューを右クリックして「3D Object」→「Cube」と選びます。

壁オブジェクトの生成

「Cube」を選択後「Inspector」ビューの「Position」の「y」を「0.5」に、「Scale」の「z」を「0.1」と入力します。 これで壁の基ができたのであとは自分の好きな位置に配置していきます。
また、この時に「Scale」の「x」の値を変更すると壁の幅を広げることができるので、長い壁を作りたい時はここを変更しましょう。
さらに壁の向きを変えたい場合は「Rotation」の「y」を「90」と変えてあげると向きを変更できます。

回転後の壁オブジェクト

生成した壁オブジェクトを「Hierarchy」内で選択後、右クリック→「Copy」をクリックし、再び「Hierarchy」内で右クリック→「Paste」と選択すると同じオブジェクトを複製できます。
複製後「Transform」の値を変更して各壁オブジェクトを配置しましょう。
今回設定した壁オブジェクトのパラメータは下記画像の通りです。

壁オブジェクトポジション一覧

時間表示をしてみよう

次に時間を表示していきます。
ゲームが開始してから何秒経っているかをカウントアップしていくものを作ります。
こちらもスクリプトで書いていくので、先ほどと同様スクリプトファイルを生成して「Timer」と名前をつけます。
ここではダウンロードした「Timer.cs」を基に説明していくので、「Timer.cs」を確認しながら実装を進めます。

ここで「Text」の参照を持つとありますが、このように「SerializeField」と書くと「Inspector」からオブジェクトを設定できるようになり、設定したオブジェクトについてスクリプトから変更(更新)ができます。
また、注意点として上部に記載してある「using UnityEngine.UI;」というものがないと「Text」が使えないので注意しましょう。

「isGoal」の値として「false」というものが設定されています。
この「false」とは、「正しくない」事を意味していて、対になるものとして「true(正しい)」があります。
(「true」,「false」は別名「真偽値」といい「true」が「真」,「false」が「偽」となります。)
現状「isGoal(ゴールしたかどうか)」は常に「false(ゴールしていない状態)」になっていますが、後々ゴールを設定する時に使うのでこのまま置いておいてください。

この「Timer」スクリプトを「Text」オブジェクトにドラッグ&ドロップしましょう。
すると「Inspector」にの一番下に「Timer」のコンポーネントが表示されます。
「Text」の参照が「None」になっているため、「None」になっている個所に「Text」オブジェクトを設定していきます。
設定の仕方は「Hierarchy」の中にある「Text」オブジェクトを「None」の場所にドラッグ&ドロップします。
すると参照のところが「None」から「Text」に変わりました。
これで設定が完了したので、時間の経過とともに「Text」が更新されるようになりました。
実際に再生して確認してみましょう。

ゴールを作ろう

キャラクターを動かすことができるようになり、時間をカウントすることもできるようになったので最後にゴールを設定していきます。
まず最初にゴール判定をとるオブジェクトを配置します。
今回も「Cube」を使って設定します。
「Hierarchy」ビューを右クリックして「3D Object」→「Cube」と選びます。

GoalObjectのパラメータ

「Cube」を選択後「Inspector」ビューの「Position」を「4,0.5,3.5」、「Scale」を「2,1,3」と入力します。
するとフィールドの右上の位置に配置できました。
また、壁のオブジェクトと名前が被ってしまうため、名前を「GoalObject」としましょう。
次に「Inspector」にある「MeshRenderer」のチェックを外します。
さらに「BoxCollider」の「isTrigger」にチェックを入れます。
こうすることで当たり判定は残したまま、オブジェクトを非表示にできます。
最後にここに当たった時の挙動をスクリプトで設定していきます。
新しくスクリプトを生成して「GoalObject」とします。

ここではダウンロードした「GoalObject.cs」を基に説明していくので、「GoalObject.cs」を確認しながら実装を進めます。

ここで「Timer.cs」内の「isGoal(ゴールしたかどうか)」を「true(ゴールしている状態)」に変更することによってカウントをストップできます。
作成した「GoalObject」スクリプトを「Hierarchy」の「GoalObject」にドラッグ&ドロップします。
この時に「GoalObject」の「Inspector」に「Timer」を設定する箇所があり、参照が「None」になっているため「Hierarchy」にある「Text」オブジェクトをドラッグ&ドロップで反映します。

実際にプレイしてみよう

play画面

これでゴールオブジェクトの所まで行くとカウントが止まるようになり、タイムアタックとして遊べるようになりました。
現状迷路と呼ぶには簡単すぎるので壁オブジェクトを増やして自分なりの難しい迷路を生成してみてください!

まとめ

少し早足になってしまった部分もありますが、Unityでゲームを作成するにあたっての第一歩を踏み出せたと思います。
UnityEditorで触る部分にしてもスクリプトにしてもまだまだ奥深い要素がたくさんあるので、ゲームを作りながら楽しく学んでいきましょう。
また違う要素についても解説していきたいと思いますので、今後の記事にご期待ください!
最後までお読みいただき、ありがとうございました!

株式会社ネックネッコ 代表取締役 野口 基之
株式会社ネックネッコ
代表取締役
野口 基之

個人でスマートフォンゲーム開発をしようと思った際にUnityと出会う。 以来Unityの素晴らしさを人々に伝えたいと思うようになり、普段はシステムエンジニアとして仕事をする傍ら、Unityの勉強会、技術者交流会の開催や、集中セミナーのアシスタント講師を行なっている。 また、技術書の執筆(マイコミジャーナルより6月に発売予定)と、日本唯一のUnity公認の認定校(バンタンゲームアカデミー)にて講師業務に従事し、未来のゲームエンジニアの育成に努めている。