Unityちゃんの障害物ゲームを作る

2014年11月13日(木)
薬師寺 国安

今回は、連載の第3回で実装したUnityちゃんが走ったり、ジャンプしたりする機能を利用して、「Unityちゃん障害物ゲーム」を作ってみたいと思います。

プロジェクトの作成

Unityメニューの[File]ー[New Project]と選択して「Unity-Project Wizard」画面を表示します。「Project Location」の「Project名」に「UnitychanObstacleGame」と指定して、「Create」ボタンをクリックします。

次に「Asset」の準備をします。同じ「Asset」を別のプロジェクトで利用したことがあれば、それを再利用することもできます。コピー元とコピー先のプロジェクトをそれぞれ起動させておき、コピー元からコピー先の「Project」内の「Assets」フォルダーにドラッグ&ドロップします。ですが、「Asset」がバージョンアップしている可能性もありますので、常に最新の「Asset」を「Import」しておくほうがいいでしょう。今回は、必要な「Asset」を「Asset Store」からダウンロードするようにしています。

Asset Storeから各種コンポーネントのダウンロード

Unityメニューの[Windows]−[Asset Store]と選択して、「Asset Store」にアクセスし、以下の3つのファイルをダウンロードします。

  1. 「”Unity-chan!” model」
  2. 「Mecanim Locomotion Starter Kit」
  3. 「Raw Mocap data for Mecanim」

これらのダウンロード方法については、連載の第3回で解説済みですので、そちらを参考にしてください。さらにUnityちゃんの配置、「Main Camera」の設定、実行時に発生するエラーの回避方法なども解説してありますので、まずはそこまで同じように設定を済ませてください。

今回は第3回までの設定に追加するかたちで、ステージの作成、所要時間の表示、そしてゴールの判定について解説していきます。

ステージの作成

まず、「Hierarchy」の「Create」から「Plane」を配置します。「Inspector」内の「Transform」の「Scale」で「X」を「20」、「Y」を「1」、「Z」を「20」と設定して、「Plane」を広くとっておいてください。次に、Unityちゃんと「Directional Light」を配置しますが、位置は連載の第3回と同じでいいでしょう。「Main Camera」の位置も同様です。「Plane」を広く取ってUnityちゃんを配置すると図1のようになります。

図1:広くとった「Plane」上にUnityちゃんを配置(クリックで拡大)

「Plane」に「Texture」を適用する

「Plane」が真っ白のままだと、Unityちゃんが動いている様子がわかりにくいので、「Texture」を適用します。「Project」内の「Unitychan」フォルダー内の「Stage」フォルダーに「Textures」というフォルダーがあり、その中に4点ほど拡張子が「png」のファイルが入っています。今回はそのうちの「unitychan tile6.jpg」を「Hierarchy」内の「Plane」上にドラッグ&ドロップします。すると「Plane」に「Texture」が適用されます(図2)。

図2:「Texture」で「Plane」に模様をつける(クリックで拡大)

これで実行してみると、右上隅に「Change Motion」、「Next」、「Back」と書かれたボタンのようなものが表示されています(図3)。これはUnityちゃんを配置してプレイ画面で実行する際に、いろいろなポーズを試すためのボタンです。今回のようにUnityちゃんをスクリプトで操作する場合は、このボタンは不要ですので、「Inspector」にある「Idle Changer(Script)」を削除して、表示を消しておきましょう。

図3:右上隅に「Change Motion」メニューが表示されている(クリックで拡大)

では、次に障害物の配置とゴールを設定しましょう。

ゴールの設定

まず、「Scene」画面の上でマウスのホイールを使って画面を縮小しておきましょう。次に「トランスフォームツールアイコン(図4)」を用いて、図5のように全体が見えるように位置を調整します。

図4:トランスフォームツール

図5:「Scene」画面全体を見渡せるようにした(クリックで拡大)

最初にゴールとゴールエリアを設定します。ここでは「Cube」を使ってゴールを作成していますが、必ずこのようにしなければならないというものではありません。読者自身が、自由にゴールの位置や形状、障害物の配置を決めていただいて構いません。

まず「Hierarchy」の「Create」から「Cube」を選択します。すると「Cube」は「Plane」の下に配置されますので、「Hierarchy」内の「Cube」をダブルクリックして位置を確認し、トランスフォームツール(図4)の左から2番目のアイコンをクリックして3方向の矢印キーを表示させて、Y軸を上方向に引っ張ってください。そして、矢印キーを使ってゴールの位置まで移動させます。

位置を決めたら、ゴールのサイズを「Inspector」の「Transform」にある「Scale」で設定します。まずは「X」に「6」、「Y」に「2」、「Z」に「6」と設定しておきますが、実際にプレイしてみながら調整するといいでしょう。またここで、「Cube」の名前を「Goal」としておきましょう。

次に「Goal」の外見を設定していきましょう。まず「Project」の「Create」から「Material」を選択し、名前を「Red」としておきます。「Inspector」内の「Main Color」を「赤系統色」に指定し、「Cube(Goal)」上にドラッグ&ドロップします(図6)。

図6:「Goal」となる「Cube」を赤に設定(クリックで拡大)

この「Goal」の上に「ゴール領域」を設定します。先ほどと同じように「Cube」を追加し、「Inspector」の「Transform」の「Scale」はそれぞれ「X」を「4」、「Y」を「5」、「Z」を「4」に設定し、名前も「GoalArea」としておきます(図7)。

図7:「Goal」の上に「GoalArea」を作る

次に、図7の「GoalArea」を選択し、「Inspector」の「Mesh Renderer」の右端の「歯車アイコン」をクリックして表示されるリストの一覧から、「Remove Component」を選択します。すると「GoalArea」が図8のように枠だけの表示になります。

図8:「GoalArea」が枠だけの表示になった

この枠は非表示になっており、実際のプレイ画面では見えません。プレイヤーが「Goal」に上がって、「GoalArea」に入ると「Goal!」と表示されるようにします。なお「GoalArea」の「Inspector」の「Box Collider」にある「Is Trigger」には、必ずチェックを入れてください。このチェックが入ってないとゴールの判定ができませんので、注意してください。

障害物の配置

続いて、障害物を配置していきます。Unityメニューの[GameObject]−[Create Empty]を選択し、「Hierarchy」内に「GameObject」を作成します。名前は「Obstacle」と指定します。

次に「Cube」を追加し、「GameObject(Obstacle)」の上にドラッグ&ドロップして、「GameObject」の子要素となるように配置してください。「Cube」を選択して、「Inspector」内の「Transform」にある「Scale」の「X」の上にマウスカーソルを持っていきます。すると、カーソルの形が「←→」に変わりますので、左右にドラッグすると「Cube」の「X」の値が変更されます。「Y」や「Z」の値も同様です。

Unityちゃんがジャンプで飛び越えられる障害物や、飛び越えられない障害物を、読者の皆さんの好きな位置に配置してください。時々「プレイ画面」で実行しながら配置していくといいでしょう。「Cube」が1個できたら、この「Cube」を選択して右クリックで表示されるメニューから「Duplicate」を選択すれば、複製できます。トランスフォームツールで好きな位置に配置してください。複製した「Cube」は元の「Cube」と同じサイズなので、「Transform」の「Scale」を調整して変更するといいでしょう。この辺りは読者が自由に配置していただいて構いません。筆者は図9のように配置してみました。

図9:障害物を配置した(クリックで拡大)

障害物にMaterialを設定する

現状では「Cube」が白一色なので、「Cube」に「Material」を設定しましょう。「Project」の「Create」から「Material」を3個追加し、それぞれ名前に「Blue」、「Green」、「Yellow」と指定しておきます。各「Material」を選択して「Inspector」の「Main Color」にそれぞれ、「青系統色」、「緑系統色」、「黄系統色」を指定して、「Scene」上に配置している「Cube」に適当にドラッグ&ドロップしていきます(図10)。

図10:障害物に色をつけてみた(クリックで拡大)

タイムの表示とゴールの判定

このゲームではプレイ中に経過時間を表示しつつ、ゴールしたら「Goal!」と表示して、時間表示を止めるようにします。

まず「Hierarchy」内の「unitychan」を選択し、「Inspector」内にある「Layer」の横の「Default」の上下▼部分をクリックし、「Add Layer」をクリックします。表示される「User Layer 8」に「Player」と入力します(図11)。

図11:「Layer」の追加

再度「unitychan」を選択し、「Inspector」内の「Layer」の「Default」から「Player」を選択します。すると、図12のように「Change Layer」の確認ダイアログが表示されるので、「Yes, change children」をクリックします。

図12:「Layer」変更のダイアログ

同様に、「Tag」にも「Player」を指定しておきます(図13)。

図13:「Tag」と「Layer」に「Player」を指定した状態

次に、「Hierarchy」から「GoalArea」を選択し、「Add Component」の「New Script」で「Name」に「GoalArea」、「Language」に「Java Script」を選択して、「Create and Add」をクリックします。すると、「GoalArea」の「Inspector」に「Goal Area(Script)」が追加され、「Script」内の「GoalArea」をダブルクリックするとMonoDevelopが起動しますので、リスト1のコードを入力します。

Playerがゴールしたかどうかの判定コード(GoalArea.js)

static var myGoal:boolean;
myGoal=false;                                   (1)

function OnTriggerEnter(myCol:Collider)
{
 if(myCol.tag=="Player")
 {
  myGoal=true;                                  (2)
 }
}
  1. static型の変数myGoalを宣言し、falseで初期化しておきます。staticは静的変数を表し、そのブロックが終了しても変数値が保持されます。myGoalは他のスクリプトからも利用されるのでstaticと宣言しておきます。
  2. OnTriggerEnterイベントでPlayerがGoalAreaに入ったかどうかを判定し、GoalAreaに入ればmyGoal変数をtrueにします。

次に「Hierarchy」の「Create」で「GUI Text」を追加します。名前は「msg」と指定します。「GUIText」の「Text」は、空にしておきます。その他「Anchor」に「upper left」、「Alignment」に「left」、「Font Size」に「80」、「Font Style」に「Bold(太字)」、「Color(文字色)」に「黄系統色」をそれぞれ指定します(図14)。

図14:「Goal」に表示する文字位置等の指定

次に、もう一個「GUI Text」を配置します。経過時間を表示するものなので、こちらは名前を「TimeText」とします。「GUIText」の中の「Pixel Offset」で、時間を表示する位置を決めます。「X」に「-500」、「Y」に「200」、そして「Font Size」には「40」と指定します(図15)。

図15:時間を表示位置の指定

次に「Add Component」で「New Script」を選び、「Name」に「myTimeScript」、「Language」に「Java Script」を選択して、「Create and Add」をクリックします。「Inspector」の「TimeText」に「myTime Script(Script)」が追加されます。「Script」の中の「myTimeScript」をダブルクリックし、MonoDevelopで、リスト2のコードを記述します。

時間を表示するコード(myTimeScript)

static var time:float;
function Start () {
 time=0;                        (1)
}

function Update () {
 myGoal();                      (2)
}

function myGoal()
{
if (GoalArea.myGoal==false)
 {
  time+=Time.deltaTime; (3)
 }else{
  var msg=GameObject.Find(“msg”);
  msg.guiText.text=”GOAL!”;     (4)
  yield WaitForSeconds (5.0);
  Application.LoadLevel(Application.loadedLevel);
 }
 var now:int=time;              (5)
 guiText.text=”<Color=red>TIME:” + now.ToString()+”</Color>”;
}
  1. 静的変数timeを宣言し、Start関数の中で「0」で初期化しておきます。
  2. Update関数からmyGoal関数を実行します。myGoal関数内では以下の処理を行います。
  3. Playerがまだゴールしていない間は、Time.deltaTimeで、前のフレームと今のフレームの時間的な差分を求めて(単位は秒)、静的変数timeに格納して加算していきます。
  4. ゴールに到達したら、「msg」というGameObjectをFindで見つけて、そのguiTextに「GOAL!」と表示します。5秒待機した後、初期画面に戻ります。
  5. 変数nowに経過する時間を代入し、guiTextに文字色を赤にして経過時間を表示します。

動画1が、実際に動かしたようすです。

動画1:ゴールを目指すUnityちゃん

今回はこれで終わりです。この「Scene」画面をUnityメニューの[File]ー[Save Scene]で保存しておきましょう。
初めてのゲームはいかがだったでしょうか。障害物やゴールの位置は読者の皆さんが自由に決めてください。また、Unityちゃんが走ったりジャンプしたりするコードは全てに共通ですので、これ以後の解説でも使用します。

次回は、Unityちゃんが障害物を破壊するゲームを紹介します。お楽しみに。

【参考文献】

浅野祐一、荒川巧也、森信虎 『Unity4入門 最新開発環境による簡単3Dゲーム制作』 SBクリエイティブ(発行年:2013)

薬師寺国安事務所

薬師寺国安事務所代表。Visual Basic プログラミングと、マイクロソフト系の技術をテーマとした、書籍や記事の執筆を行う。
1950年生まれ。事務系のサラリーマンだった40歳から趣味でプログラミングを始め、1996年より独学でActiveXに取り組む。1997年に薬師寺聖とコラボレーション・ユニット PROJECT KySS を結成。2003年よりフリーになり、PROJECT KySS の活動に本格的に参加、.NETやRIAに関する書籍や記事を多数執筆する傍ら、受託案件のプログラミングも手掛ける。Windows Phoneアプリ開発を経て、現在はWindows ストア アプリを多数公開中

Microsoft MVP for Development Platforms - Client App Dev (Oct 2003-Sep 2012)。Microsoft MVP for Development Platforms - Windows Phone Development(Oct 2012-Sep 2013)。Microsoft MVP for Development Platforms - Client Development(Oct 2013-Sep 2014)。Microsoft MVP for Development Platforms-Windows Platform Development (Oct 2014-Sep 2015)。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています