Unity 5でコインプッシャーゲームを作ろう(後編)

2015年8月19日(水)
古波倉 正隆(こはぐら まさたか)

前回まで、前編・中編とコインプッシャーゲームを製作してきましたが、後編の今回はいよいよ仕上げに入ります。ゲームのメインとなるコインの動作に関するスクリプトを中心に記述していきます。

今回は、以下のことを習得します。

  • テキスト(コインの枚数)を表示してみる(uGUIの利用)
  • コインの枚数を増減させる(Textをスクリプトで制御、他のGameObjectに付けたスクリプトを呼ぶ)
  • コインが土台から落ちたときの処理(Tagの利用)
  • コインが土台から落ちて加点したときに効果音を鳴らす
  • Assetを利用して、ステージを飾ってみよう(Asset Storeの利用)

テキスト(コインの枚数)を表示してみる(uGUIの利用)

Unity 4.6から実装されたUnityのUIシステムです。このUIシステムは正式名称ではないのですが、「uGUI」という名称が使用されていることがほとんどなので、本稿でも「uGUI」という名称で紹介していきます。

それでは、uGUIを使用してコイン枚数を表示できるようにしましょう。ヒエラルキーウィンドウから[Create]→[UI]→[Text]を選択してください(図1)。「Canvas」というオブジェクトができ、その下に「Text」というオブジェクトができます。このTextオブジェクトを「ScoreText」と名付けます(図2)。

uGUIのTextの追加

図1:uGUIのTextの追加

Textオブジェクトを「ScoreText」と名付ける

図2:Textオブジェクトを「ScoreText」と名付ける

uGUIではCanvas上にボタンやテキスト、画像を並べてUIを製作していきます。それでは、作ったScoreTextをダブルクリックしてみましょう。ゲームシーンの中に、現在製作中のコインプッシャーゲームとCanvasが共存しています。ここで、ScoreTextが白枠内へ収まるように、設置したい場所に配置してください。筆者は今回、白枠内左下にコインの枚数を表示するようにしました。なお、白枠はゲーム実行時のウィンドウサイズと同じ大きさになっています(図3)。

uGUIの配置(白枠の左下に配置)

図3:uGUIの配置(白枠の左下に配置)

ScoreText設置時は文字が小さく、文字色も黒で見難いかと思われるので、文字を大きくかつ文字色も変更しましょう。ScoreTextのInspectorで、「Font size」を見やすいサイズに変更します。なお、フォントを大きくしすぎると先ほどまで表示されていた「New Text」が表示されなくなってしまうと思います(図4)。これは、ScoreTextのテキストサイズが表示される枠内に収まりきらなかったためです。

そこで、Paragraph内の「Best Fit」にチェックマークを付けましょう。これにより、自動的に枠の大きさをフォントサイズに合わせて変更してくれます(図5)。

フォントを大きくすると文字が表示されなくなる

図4:フォントを大きくすると文字が表示されなくなる

ScoreTextのインスペクタウィンドウ

図5:ScoreTextのインスペクタウィンドウ

[Game]タブをクリックして、実際にScoreTextがどのように配置されているか見てみましょう(図6)。

[Game]タブに切り替えてScoreTextがどのように配置されているか確認

図6:[Game]タブに切り替えてScoreTextがどのように配置されているか確認

コインの枚数を増減させる(Textをスクリプトで制御、他のGameObjectに付けたスクリプトを呼ぶ)

ここからは、スポーナーからコインを生成する際に、コインの表示を減らすスクリプトを書いていきます。なお、本稿ではコインの枚数を「スコア」と表現します。

まず、[Project]→[Create]→[C#Script]と選択して「ScoreScript」という名前でC#スクリプトを作りましょう。そして、このScoreScriptをドラッグ&ドロップでScoreTextに貼り付けてください。

それでは、スクリプトを記述していきます。ScoreScriptをダブルクリックしてエディタを開き、リスト1のように記述しましょう。

リスト1:ScoreScript.cs

using UnityEngine;
using System.Collections;
/*
 * Textの文字列やフォントの大きさをスクリプトで変更する際には、
 * using UnityEngine.UI;を記述する必要がある。
 */
using UnityEngine.UI;

public class ScoreScript : MonoBehaviour {

	/*
     * Scoreの初期値(最初に持っているコインの枚数)を
     * インスペクタ上から設定できるようにpublic 変数で宣言しておく
     */
	public int initScore;
	int currentScore;
	Text scoreText;
	
	void Start () {
		currentScore = initScore;
		scoreText = this.GetComponent<Text>();
		printScore(initScore);
	}
	
	// スコアを減点する関数
	public void subScore(int n) {
		currentScore -= n;
		printScore(currentScore);
	}
	
	// スコアを加点する関数
	public void addScore(int n) {
		currentScore += n;
		printScore(currentScore);
	}
	
	void printScore(int n) {
		/*
         * ScoreTextのTextに整数を代入する。
         * scoreText.textはstring型(文字列)を受け取るが、nはint型(整数)なので、
         * nをstring型に変換してあげる必要がある。
         */
		scoreText.text = n.ToString();
	}
}

また、subScore関数とaddScore関数はScore以外のスクリプトから呼び出せるようにしたいです。具体的に言えば、スポーナーからコインが生成されるときに、スコアからコインを生成した枚数分だけ減点するようにしたいところです。

そこで、Spawnerに貼りつけたSpawnerScriptから、ScoreTextに貼りつけたScoreScriptのsubScore関数を呼び出せるようにしてみましょう。ProjectウィンドウのAssets内から前回作成したSpawnerScriptを開き、リスト2のように記述を追加してください

リスト2:SpawnerScript.cs

using UnityEngine;
using System.Collections;

public class SpawnerSrcipt : MonoBehaviour {

	float moveSpeed = 2.0f;
	Rigidbody rb;
	/* 追加
     * public で変数宣言をすると、インスペクタ上に項目が表示される。
     * ここではcoin という変数がインスペクタ上で表示される。
     */
	public GameObject coin;
	
	/*
     * シーンに置いたLeftWall 、RightWall をこのスクリプトで使用する。
     * また、それぞれのx 座標の変数も準備しておく。
     */
	public GameObject leftWall;
	public GameObject rightWall;
	float leftWallPositionX;
	float rightWallPositionX;

	// scoreTextをインスペクタ上に表示させる
	public GameObject scoreText;
	ScoreScript scoreS;
	
	void Start () {
		// スクリプトを付けたゲームオブジェクトのRigidbodyコンポーネントを取得する
		rb = this.GetComponent<Rigidbody>();
		// leftWall とrightWall のx 座標を取得
		leftWallPositionX = leftWall.transform.position.x;
		rightWallPositionX = rightWall.transform.position.x;

		/*
         * scoreText内にあるScoreScriptをgetComponentで取ってくる。
         * これで、ScoreScript内にてpublicで宣言した関数を利用できるようになる。
         */
		scoreS = scoreText.GetComponent<ScoreScript>();
	}

	// Update is called once per frame
	void Update () {

		/*
         * Mathf.Clamp である変数の最小値と最大値を設定することができる。
         * 第一引数は設定したい変数、第二引数は最小値、第三引数は最大値である。
         * Spawner の移動できるx 座標範囲をleftWallPosition のx 座標から、rightWallPostion のx 座標の範囲にしている。
         */
		Vector3 currentPosition = this.transform.position;
		currentPosition.x = Mathf.Clamp(currentPosition.x,
		                                leftWallPositionX,
		                                rightWallPositionX);
		this.transform.position = currentPosition;

		/*
         * Inputクラスは入力システムに関する関数が含まれている。
         * GetAxisでPCの矢印キーの入力を受け付けることができる。
         * "Horizontal"だと、左右の矢印キーの入力を受け付け、"Vertical"だと
            上下の矢印キーの入力を受け付けるようになる。
         * http://docs.unity3d.com/ja/current/ScriptReference/Input.GetAxis.html
         */
		float x = Input.GetAxis ("Horizontal");
		
		// キー入力された際の移動する向きを決める。
		// 今回はx軸方向に移動させたい
		Vector3 direction = new Vector3 (x, 0, 0);
		
		// velocity(速度)に代入することによって、このオブジェクトの移動速度が決定される
		rb.velocity = direction * moveSpeed;

		/* 
         * スペースキーが押されたときにcoin を生成する。
         * 第一引数は生成するオブジェクト、第二引数は生成する場所、
           第三引数は生成する角度
         */
		if (Input.GetKeyDown("space")) {
			Instantiate(coin,this.transform.position,this.transform.rotation);
			// スペースキーが押されたら、スコアを1点減点させる
			scoreS.subScore(1);
		}
	}
}

スクリプトを記述した後は、SpawnerのインスペクタウィンドウにあるSpawner Scriptに「Score Text」という項目が出現しているので、そこにScoreTextをドラッグ&ドロップします。ここまで完了したら、ゲームを実行してみましょう。スペースキーを押すたびにスコアが減少していきます(図7)。

左下に設置したScoreTextが減点されていく様子

図7:左下に設置したScoreTextが減点されていく様子

コインが土台から落ちたときの処理(Tagの利用)

ここまでの操作で、スポーナーからコインが生成されたときにスコアが減点される様子を確認できました。次は、コインが土台から落ちた時にスコアを増加させてみましょう。ここでは、ほとんどのコインプッシャーゲームと同様に、土台より手前にコインが落ちたらスコアを増加するようにします。

まずは、シーンビューで土台の下に受け皿を設置しましょう。[Hierarchy]→[Create]→[3DObject]→[Cube]と選択して受け皿を作成します。CubeのScaleは土台に合わせてX=5、Y=1、X=5に設定し、名前を付けましょう。筆者は「Saucer」と名付けました(図8)。

Saucerの設置

図8:Saucerの設置

次に、この受け皿にコインが乗ったらスコアを2増加し、受け皿に乗ったコインを消す処理を記述します。先ほどと同じように[Project]→[Create]→[C#Script]と選択して「SaucerScript」という名前でC#スクリプトを作り、リスト3のように書いていきましょう。そして、SaucerScriptをドラッグ&ドロップでSaucerに貼りつけます。

リスト3:SaucerScript.cs

using UnityEngine;
using System.Collections;

public class SaucerScript  : MonoBehaviour {

    void OnCollisionEnter(Collision colObject) {
    // Saucerと衝突したオブジェクト(colObject)の「名前」が"Coin"だったときに、
    // 衝突したオブジェクトを消す(Destroy)
        if (colObject.gameObject.name == "Coin") {
            Destroy(colObject.gameObject);
        }
    }
}

ここで、再度ゲームを実行してみましょう。スペースキーを押しても生成されたコインが消えません。これは、SpawnerScriptでInstantiate関数を使用してオブジェクトを生成すると、オブジェクト名の後ろに(Clone)と付いてしまうからです(本来はInstantiate後に名前を変更することも可能)。

そうなると、if文内のCoinとオブジェクト名が一致しなくなってしまうため、受け皿とぶつかってもコインが消えません(図9)。そのため、別の方法で名前を一致させてコインが消えるようにする必要があります。

Saucerに衝突してもCoin(Clone)が消えない

図9:Saucerに衝突してもCoin(Clone)が消えない

そこで、タグ機能を使います。タグ機能を使うと、CoinとCoin(Clone)を同じオブジェクトに分類分けすることができます。

タグ機能は、複数のゲームオブジェクトを分類分けするために使用します。例えば、敵キャラクターが「ゴブリン」「スライム」「ドラゴン」と3体いたとして、タグを使うとこれら3体をまとめて「Enemy」と設定できます。

それでは、プロジェクトウィンドウのAssets内にある「Coin」をクリックしてください。続いてInspectorの「Coin」とオブジェクト名が表示されている下にある「Tag」の[Untagged]という項目をクリックし、[AddTag…]を選択します(図10)。

Tagを設定する場所

図10:Tagを設定する場所

インスペクタウィンドウが「Tags&Layers」という表示に変わり、ここでユーザが定義してタグを作ることができます。「Tags」が「List is Empty」になっているはずですので、[+]を押して新しいタグを作ります。作成したTagに「Coin」と名付けて(図11)、プロジェクトウィンドウのAssets内にあるCoinの[Tag]を「Coin」に変更しましょう(図12)。

Tagの編集ウィンドウ(Coinタグ作成後)

図11:Tagの編集ウィンドウ(Coinタグ作成後)

Coinの[Tag]を「Coin」に変更

図12:Coinの[Tag]を「Coin」に変更

ここまでの設定に合わせて、SaucerScriptも書き直します(リスト4)。

リスト4:SaucerScript.csを修正(コインが消えるスクリプトを追加)

using UnityEngine;
using System.Collections;

public class SaucerScript : MonoBehaviour {

    void OnCollisionEnter(Collision colObject) {
        // 変更 :Saucerと衝突したオブジェクトの「タグ」が"Coin"だったときに、
        // 衝突したオブジェクトを消す(Destroy)
        if (colObject.gameObject.tag == "Coin") {
            Destroy(colObject.gameObject);
        }
    }
}

これで、受け皿にコインが落ちた時に消えるようになりました。続けて、受け皿にコインが落ちたときにスコアが2点加点されるスクリプトを追加します(リスト5)。

リスト5:SaucerScript.csを修正(スコアを加点するスクリプトを追加)

using UnityEngine;
using System.Collections;

public class SaucerScript : MonoBehaviour {

	// 追加:scoreTextをインスペクタ上に表示させる
	public GameObject scoreText;
	ScoreScript scoreS;
	
	void Start() {
		scoreS = scoreText.GetComponent<ScoreScript>();
	}
	
	void OnCollisionEnter(Collision colObject) {
		if (colObject.gameObject.tag == "Coin") {
			Destroy(colObject.gameObject);
			// 追加
			scoreS.addScore(2);
		}
	}
}

スクリプトを修正したら、ヒエラルキーウィンドウ内の「ScoreText」を、SaucerのインスペクタウィンドウにあるSaucerScriptの「ScoreText」にドラッグ&ドロップすることを忘れないでください。

これで、コインプッシャーゲームがひと通り完成しました!

コインが土台から落ちて加点したときに効果音を鳴らす

ゲームがひと通り完成したところで、少しアレンジしてみましょう。コインをゲットしたときに効果音を鳴らします。効果音が鳴るタイミングは、先ほど実装した「コインが受け皿に落ちたとき」です。

まず、効果音をフリーのサイト、もしくは自前で準備してください。準備した素材をUnityのプロジェクトに追加する方法は、入れたい素材をプロジェクトウィンドウにドラッグ&ドロップして取り込むだけです(図13)。

効果音をドラッグ&ドロップでUnityプロジェクトに追加

図13:効果音をドラッグ&ドロップでUnityプロジェクトに追加

追加した効果音ファイルは波形のアイコンで表示されます。波形のアイコンが音に関するファイルになります。

それでは、取り込んだ効果音を鳴らすための準備をしましょう。まず、Saucerのインスペクタウィンドウから[Add Component]→[Audio]→[Audio Source]を選択して、インスペクタウィンドウに「Audio Source」を付けます。次に、Audio Source内の「AudioClip」に取り込んだ効果音をドラッグ&ドロップします。なお、「Play On Awake」のチェックマークは外してください(図14)。

Saucerのインスペクタウィンドウの状態(Audio Source追加後)

図14:Saucerのインスペクタウィンドウの状態(Audio Source追加後)

ここから、SaucerScriptにコインが落ちたときに音を鳴らすスクリプトを追加します(リスト6)。

リスト6:SaucerScript.csを修正(効果音を鳴らすスクリプトを追加)

using UnityEngine;
using System.Collections;

public class SaucerScript : MonoBehaviour {

    // 追加 :scoreTextをインスペクタ上に表示させる
    public GameObject scoreText;
    ScoreScript scoreS;

    AudioSource getSE;

    void Start() {
        scoreS = scoreText.GetComponent<ScoreScript>();
        // 追加 : Saucerに付けたAudioSourceコンポーネントをとってくる
        getSE = this.GetComponent<AudioSource>();
    }

    void OnCollisionEnter(Collision colObject) {
        if (colObject.gameObject.tag == "Coin") {
            Destroy(colObject.gameObject);
            scoreS.addScore(2);
            // 追加 : PlayOneShotでAudioClipに入れた音を一度だけ鳴らす
            getSE.PlayOneShot(getSE.clip);
        }
    }
}

これで、コインが受け皿に落ちたときに効果音が鳴るようにできました。

アセットストアを利用してステージを飾ってみよう(AssetStoreの利用)

Unity社が提供する「アセットストア」では、ゲーム製作に利用できる3Dモデルや音源、画像などをダウンロードできます(無料・有料)。どのような素材があるか、実際にアセットストアを覗いてみましょう。メニューバーから[Window]→[Asset Store]を選択すると(図15)、別ウィンドウで画面が表示されます。これがアセットストアです。画面右側にある「3Dモデル」「アニメーション」「エディタ拡張」「オーディオ」などから、さまざまな素材や拡張を購入することができます(図16)。

メニューバーから「アセットストア」を開く

図15:メニューバーから「アセットストア」を開く

「アセットストア」のトップページ

図16:「アセットストア」のトップページ

アセットストアから素材をダウンロードするには、アセットストアにログインしなければなりません。アセットストアの右上にある[ログイン]から、本連載の第1回で作成したUnityのアカウントを使ってログインしましょう。

無事にログインできたら、自分の欲しい素材や拡張を探します。例えば、コインのアセットが欲しい場合は、画面右上の検索欄(Asset Storeをサーチする)に「Coin」と打ち込みます。このとき、日本語だとほとんど出てこないので、英語で検索してください。

検索結果を見ると、他の製作者が作ったコインがたくさん表示されます(図17)。ここから無料のものを選んでダウンロードしてみるのも良し、有料のアセットを購入してみるのも良いでしょう。

「Coin」の検索結果

図17:「Coin」の検索結果

ここでは、「Gold Coins」という無料で利用できるアセットをダウンロードして、コインプッシャーゲームのプロジェクトに入れてみます。

検索結果から「Gold Coins」をクリックし、遷移した画面で[ダウンロード]を押すとダウンロードが始まります(図18)。ダウンロードが終了すると、図19のようなウィンドウが表示されます。

「Gold Coins」のダウンロードページ

図18:「Gold Coins」のダウンロードページ

ダウンロードの終了画面

図19:ダウンロードの終了画面

ここで[import]ボタンをクリックすると、アセットがUnityのプロジェクト内に取り込まれます。ダウンロードしたGold Coinsをさっそくコインプッシャーゲームに利用してみました(図20)。見た目にも、より本物のゲームらしくなったのではないでしょうか。

コインプッシャーゲームに「Gold Coins」を適用してみた

図20:コインプッシャーゲームに「Gold Coins」を適用してみた

ここまで、3回にわたってコインプッシャーゲームを製作してきました。お疲れ様でした。皆さんも、上手に製作できたでしょうか?

本連載で紹介した機能はごく一部で、Unityはまだまだたくさんの機能があります。幸いにもUnityは多くの情報がネット上にありますので、目的に応じて実装方法を調べ、さまざまなジャンルのゲーム製作にもチャレンジしてみてください。

そして、本連載が1人でも多くの方々にとって、ゲームを作るための一歩となれば嬉しいです。

次回は、複数人で1つのUnityプロジェクトを管理する方法について解説します。

著者
古波倉 正隆(こはぐら まさたか)
琉球大学大学院、IGDA 琉球大学代表

2歳の頃から叔父の影響でファミコンを触り始める。5歳の頃に初代ぷよぷよにハマり、そこからゲーム好きが開花。ノベルゲーム以外の幅広いジャンルをプレイしてきた。 大学ではゲーム開発者向けコミュニティ IGDA琉球大学 を設立し、ゲーム開発者向けに講演会やゲームジャムを開催している。 好きなゲームは KOEI 三国志・信長シリーズ、KONAMI 系音ゲなどなど。
個人ブログ(masakoha’s room) : http://www.masakoha.com/

連載バックナンバー

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

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

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

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