標的をマシンガンで撃ち落とす本格的なUnityゲーム作りに挑戦してみよう

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

今回は標的をマシンガンで連射して、床の外に落下させるまでの時間を競うゲームを作ります。

プロジェクトの作成

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

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

まず必要なものをAsset Storeから入手しましょう。「Asset Store」の検索欄に「Animated Soldier」と入力し、表示される画面で「Import」をクリックします(図1)。

3Dモデルの「Animated Soldier」を入手

図1:3Dモデルの「Animated Soldier」を入手(クリックで拡大)

すると「Importing package」の画面が表示されますので、「Import」をクリックします(図2)。

「Import」をクリックする

図2:「Import」をクリックする

ダウンロードが終了すると、「Project」の「Assets」フォルダーの下に「Cartoon Soldier」フォルダーが作成されています(図3)。

「Cartoon Soldier」フォルダーが作成された

図3:「Cartoon Soldier」フォルダーが作成された

もう一つ、今度はマシンガンのサウンドファイルをダウンロードします。「Asset Store」で「Futuristic weapons set」を検索すると「Futuristic weapons set」の画面が表示されますので、「Import」をクリックします。その後、「Importing package」の画面が表示されますので、「Import」をクリックします。ダウンロードが完了すると、「Project」の「Assets」フォルダーの下に、「FuturisticWeaponsSet」フォルダーが作成されています(図4)。

「FuturisticWeaponsSet」フォルダーが作成された

図4:「FuturisticWeaponsSet」フォルダーが作成された

ステージを作る

では、早速ステージを作っていきましょう。まず床となるCubeを配置します。名前は「Inspector」から「Floor」とつけておきます。同じく「Directional Light」も追加しておきましょう。「Floor」の「Transform」内の値は、表1のように設定します。

表1 「Transform」内の値

PositionX=7Y=1Z=7
RotationX=0Y=0Z=0
ScaleX=30Y=1Z=40

次に、「Main Camera」の位置を表2のように指定します。

表2 「Transform」の値

PositionX=-2.0Y=3.6Z=-5.8
RotationX=0Y=0Z=0
ScaleX=1Y=1Z=1

次に、「Floor」に「Texture」を適用させます。ダウンロードした「Cartoon Soldier」フォルダー以下の「Texture」内に、各種テクスチャがあります。今回は、その中から「dirt.tga」を選んでみました(図5)。

テクスチャを適用した「Floor」

図5:テクスチャを適用した「Floor」(クリックで拡大)

射撃の対象となるオブジェクトを配置する

射撃の対象となるオブジェクトも「Cube」で作成します。いつもの手順で「Cube」を追加し、「Inspector」から名前に「Cube1」と指定して下さい。そして、図6の「Tag」メニューから「Add Tag」を選択します。

「Add Tag」を選択する

図6:「Add Tag」を選択する

タグ追加の画面(図7)では、「Element0」に「Cube1」と入力します。

「Element0」に「Cube1」と入力した

図7:「Element0」に「Cube1」と入力した

「Hierarchy」から「Cube1」を選択し、「Tag」に「Cube1」を指定します(図8)。

「Tag」に「Cube1」を指定した

図8:「Tag」に「Cube1」を指定した

次に、「Add Component」を選択し、[Physics]ー[Rigidbody]と選択して、「Rigidbody」を追加します。これは「重力」を表し、これを追加しておかないと、銃で撃っても標的が動きません。

「Cube1」と同じ手順で、あと2つのCubeを追加し、それぞれ名前を「Cube2」、「Cube3」とします。それぞれの「Tag」に「Cube2」、「Cube3」を追加しますが、「Cube2」のタグは「Element1」に、「Cube3」のタグは「Element2」追加してください。同じように、「Rigidbody」もそれぞれの「Cube」に追加してください。

3個の「Cube」の配置が済んだら、「Cube」にも「Texture」を適用しましょう。

標的用のテクスチャをダウンロードする

「Asset Store」のカテゴリから「Textures & Materials」を選択します。今回はその中の「Metal Textures Pack」を選択して、いつもの手順で「Import」してください。「Importing package」で「Import」すると「Project」の「Assets」フォルダーに、「Metal textures pack」というフォルダーが作成され、その中に多くの「pattern」フォルダーが作られます。今回は「pattern24」フォルダー内のテクスチャを適用します。「Scene」画面上の各「Cube」にドラッグ&ドロップしてください。この辺りは、読者が自由に指定して下さい。テクスチャを適用すると、図9のようになりました。

3つの標的(Cube1~Cube3)にテクスチャを適用した

図9:3つの標的(Cube1~Cube3)にテクスチャを適用した(クリックで拡大)

では、次にマシンガンを持った兵士を配置します。

マシンガンを持った兵士の配置

ダウンロードされた「Cartoon Soldier」フォルダー以下にある、「Prefabs」フォルダー内の「soldier」フォルダー内の「soldier3rdPerson.prefab」を、「Scene」画面上に配置します(図10)。

マシンガンを持った兵士を配置した

図10:マシンガンを持った兵士を配置した(クリックで拡大)

もう、これだけで兵士を動かし、マシンガンを撃つことができます(動画1)。画面内でマウスの左ボタンをクリックすれば、マシンガンを発射し、ボタンを押し続ければ、連射されます。

動画1:マシンガンを連射する兵士

このように動かすことはできますが、まだサウンドの処理を指定していないので、音が出ていません。これにマシンガンの音を追加しましょう。

マシンガンの音を追加する

まず「Hierarchy」から「soldier3rdPerson」を選択します。続いて「Inspector」の「Add Component」から[Audio]ー[Audio Source]と選択すると、「Inspector」内に「Audio Source」が追加されます(図11)。「Play on Awake」のチェックは、付けたままだと実行するだけで射撃音が発生しますので、必ずはずしておきます。

「Audio Source」が追加された

図11:「Audio Source」が追加された

図11の「Audio Clip」の右端にある小さな「◎」をクリックします。すると「Select AudioClip」の画面が表示されますので、今回はその中から「shot_machinegun 1」を選択します(図12)。

「Select AudioClip」から「shot_machinegun 1」を選択

図12:「Select AudioClip」から「shot_machinegun 1」を選択(クリックで拡大)

次にScriptを追加します。「Add Component」から[New Script]と選択し、「Name」に「gunSoundScript」と指定し、「Language」には「Java Script」を選択して「Create and Add」をクリックします。すると「Inspector」内に「Gun Sound Script(Script)」が追加されます。「script」の「gunSoundScript」をダブルクリックして、MonoDevelopを起動し、リスト1のコードを記述します。

マシンガンの音を出す処理(gunSoundScript.js)

var myClip:AudioClip;                   (1)

function Update () {
 if(Input.GetMouseButtonDown(0))        (2)
 {
        audio.loop=true;
        audio.PlayOneShot(myClip);      (3)
        audio.Play();

 }
 if(Input.GetMouseButtonUp(0))          (4)
 {
  audio.loop=false;
  audio.Stop();
 }
}
  1. AudioClip型の変数myClipを宣言します。
  2. マウスの左ボタンが押された時の処理です。audioのloopをtrueに指定します。クリックを止めるまで射撃音を出し続けます。
  3. オーディオの再生にはPlayOneShotを使用し、引数に「Inspector」で指定した「AudioClip」を指定します。そしてPlayで再生を実行します。
  4. マウスの左ボタンが上げられたときは、audioのloopをfalseに指定し、オーディオを停止します。

終了後に、必ずビルドを実行しておいてください。

では、これで実行してみましょう(動画2)。ちゃんと射撃音が追加されました。

動画2:射撃音が追加された

標的の残り数と経過時間を表示する

残りの標的の個数と、経過時間を表示する領域を設定します。

まず、「Hierarchy」の「Create」から「GUIText」を選択します。名前は「TimeText」とし、「GUIText」の各項目は図13のように設定します。

「TimeText」の各項目の設定

図13:「TimeText」の各項目の設定

「Pixel Offset」は経過時間の表示位置を、「Font Size」は文字サイズを指定します。

次に、もう1個「GUIText」を追加します。名前は「msg」と指定します。こちらには「Cube」の残数を表すもので、図14のように設定します。

「msg」の各項目の設定

図14:「msg」の各項目の設定

「Font Style」には「Bold」を指定して「太字」とします。「Color」は文字色になります。残りの標的の数と、経過時間を表示するための設定は、これで終わりです。

次に床の外側である「OutArea」の設定を行います。

オブジェクトがFloorから落ちた時の領域の設定

床の外側も「Cube」で作成します。「Hierarchy」から「Cube」を配置し、名前を「OutArea」と指定します。「Transform」の各値は、表3のように設定します。

表3 「OutArea(Cube)」の「Transform」の値

PositionX=7Y=-33Z=7
RotationX=0Y=0Z=0
ScaleX=1000Y=5Z=1000

表3を設定すると、図15のように表示されます。周囲の白く表示されている部分が「OutArea」になります。

「OutArea」を設定した

図15:「OutArea」を設定した

プレイ中、この白い「OutArea」は見える必要はありませんので、「OutArea」の「Inspector」内にある「Mesh Renderer」の右端にある「歯車アイコン」をクリックして「Remove Component」を選択して、非表示にします(図16)。

「OutArea」を非表示にした

図16:「OutArea」を非表示にした

「OutArea」の「Insperctor」の「Box Collider」にある「Is Trigger」には、必ずチェックを入れておいてください。後ほど、これに追加するスクリプトで当たり判定をしますので、チェックがないと当たり判定ができません。

では経過時間の表示と、床から落ちてオブジェクトの個数が減っていくScriptを記述します。

スクリプトを記述する

「Hierarchy」から「OutArea」を選択し、「Inspector」の「Add Component」で「OutArea」という名前のScriptを追加します。

「Inspector」内に追加された「Script」の「OutArea」をタブルクリックして、リスト2のコードを記述します。

標的(Cube)が「OutArea」内に入ったかどうかの判定処理(OutArea.js)

static var myOutArea:boolean;                   (1)
static var no:int;                              (2)
static var flag1:boolean;
static var flag2:boolean;                               (3)
static var flag3:boolean;
function Start () {                             (4)
 no=3;
 flag1=false;
 flag2=false;
 flag3=false;
}

function OnTriggerEnter(myCol:Collider)         (5)
{
 if (myCol.tag=="Cube1")
 {
  myOutArea=true;
  flag1=true;
 }

 if (myCol.tag=="Cube2")
 {
  myOutArea=true;
  flag2=true;
 }

 if (myCol.tag=="Cube3")
 {
  myOutArea=true;
  flag3=true;
 }
}
  1. boolean型の静的変数myOutAreaを宣言します。
  2. int型の静的変数noを宣言します。
  3. boolean型の静的変数、flag1~flag3を宣言します。
  4. 静的変数noを3で、flag1~flag3をfalseでそれぞれ初期化します。
  5. OnTriggerEnterイベントで、オブジェクトがOutAreaに入ったかどうか判定します。
    TagがCube1のオブジェクトがOutAreaに入ったら、myOutAreaとflag1をtrueに変更します。Cube2とCube3についても同様です。
    最後に必ずビルドを行ってください。

次に、「Hierarchy」から「TimeText」を選択し、「Add Component」から「TimeText」スクリプトを追加します。「Inspector」に追加された「Script」の「TimeText」をダブルクリックして、リスト3のコードを記述します。

オブジェクトの残数と経過時間を表示する処理(TimeText.js)

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

function Update ()
{
 if( OutArea.myOutArea==false || OutArea.flag1==false || OutArea.flag2==false || OutArea.flag3==false){
  time+=Time.deltaTime;                 (2)
 }
 var now:int=time;
 guiText.text="<Color=red>TIME:"+ now.ToString()+"</Color>";    (3)
}
  1. 静的変数timeを宣言し、Start関数内で0に初期化しておきます。
  2. OutAreaスクリプトの中で宣言していた静的変数myOutArea、flag1~flag3のいずれかがfalseの場合は、経過時間を表示します。
  3. 変数nowに経過時間を代入し、guiText.textに経過時間を「赤」で表示します。
    終了後には、ビルドが必要です。

最後に、「Hierarchy」から「Cube1」を選択し、「Inspector」内の「Add Component」で「CubeDisappear」というスクリプトを追加し、標的がOutAreaに落ちた際の処理を記述します。コードはリスト4のとおりです。

標的(Cube)の残数を表示し、全て床から落ちると最初から始める処理(CubeDisappear.js)

function OnTriggerEnter(col:Collider) {
 if (OutArea.myOutArea==true)
 {
  OutArea.no--;                                         (1)
  var msg=GameObject.Find("msg");
  msg.guiText.text="残り:"+OutArea.no.ToString();       (2)
  GoCheck();                                            (3)
 }
}

function GoCheck()
{
 if(OutArea.no==0)                                      (4)
    {
    yield WaitForSeconds (5.0);
    Application.LoadLevel(Application.loadedLevel);
    }
}
  1. もし、OutAreaスクリプトで宣言していた静的変数myOutAreaがtrueなら、OutAreaスクリプト内で宣言していた静的変数noの値を1ずつ減算します。
  2. GUI Textである「msg」という領域に、残数を表示します。
  3. GoCheckを実行します。
  4. noの値が0になれば、5秒後にまた最初からゲームを開始します。
    いつものように、終了後はビルドが必要です。

「Cube2」と「Cube3」でも各「Cube」を選択し、「Add Component」から「Scripts」を選択して表示される「CubeDisappear」を選択します。これで、「Cube2」と「Cube3」にスクリプトが追加されます。

では、この「Scene」画面を、Unityメニューの[File]ー[Save Scene as]と選択して、「マシンガンでオブジェクトを落とす」という名前で保存しておきましょう。

完成品は動画3のようになります。

動画3:完成版には経過時間と残りの標的数が表示される

これで6回にわたったUnityの解説は終わりです。まだまだ解説していない部分もありますが、その部分については、また別の機会があれば紹介したいと思います。

ほんの数十行のコードを書くだけで、これほどのことができるとは、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メルマガ会員のサービス内容を見る

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