猫でもわかるUnity入門(第15回 玉転がし作成 その7)

f:id:enia:20210228230354p:plain

えにあです。猫でもわかるUnity入門第15回を進めていきます。

前回はプレイヤーオブジェクトがアイテムを収集できるよにしました。 今回は収集したアイテムの数を画面に表示できるようにしていきましょう。

目次

テキストオブジェクトを追加しよう

文字を画面に表示するためには、テキストオブジェクトを使います。 テキストオブジェクトの追加はトップメニューから「ゲームオブジェクト」->「UI」->「テキスト」で行います。
f:id:enia:20210302145439p:plain

ヒエラルキービューを見てください。 Textを追加したつもりが、CanvasやEventSystemなども一緒に追加されています。
f:id:enia:20210302145641p:plain

テキストを表示するために必要なものが自動的に追加されるようです。 重要なことは、UIを動作させるためには、Canvasの子にする必要があるということです。 ここではまず、それだけ覚えておきましょう。

収集したアイテムの数を表示するテキストですので、Textオブジェクトの名前を「Count Text」に変更しておきます。
f:id:enia:20210302184228p:plain

フォントの色を白に変更しておきましょう。インスペクターで色の横にある四角をクリックします。
f:id:enia:20210302184411p:plain

RGBを(255, 255, 255)に設定します。
f:id:enia:20210302184841p:plain

一度ここでプレイモードにして動かしてみましょう。 画面の中央にテキストが表示されていますね。
f:id:enia:20210302185151p:plain

しかし、テキストは常に画面の中央に位置しています。 これでは邪魔なので画面の左上に配置させましょう。

インスペクターで「Rect Transform」->「左側の四角」を選択すると、アンカープリセットがのポップアップが表示されます。
f:id:enia:20210302185338p:plain

現在は真ん中に設置されてることが分かりますが、何を基準にした真ん中なのでしょう。 これはCanvasに対して真ん中になります。 Canvasは画面全体にオーバーレイされているので、画面の中心に配置されるわけです。

画面の左上にテキストを表示するために「left-top」に変更します。 「left-top」を選択する際、「Shift + Alt」を押しながら選択してください。 ポップアップに説明が記載されていますが、Shiftを押すことでピボットを、Altを押すことで位置を設定してくれます。
f:id:enia:20210302193128p:plain

さあ、もう一度実行してみましょう。画面の左上に表示されますね。
f:id:enia:20210302193515p:plain

しかし、ピッタリ左上にくっついてしまっているので、少し余白を作りましょう。 インスペクターで位置(X, Y)をそれぞれ(10, -10)に変更します。 Canvasが画面全体に対してオーバーレイされていて、左上が(0, 0)になっており、右に行くほどX軸がプラスに、下に行くほどY軸がマイナスになるようです。
f:id:enia:20210302200508p:plain

さあ、もう一度実行してみましょう。いい感じに表示されましたね!
f:id:enia:20210302200915p:plain

カウントを更新しよう

PlayerControllerスクリプトを修正して、アイテムを取得する度にカウントCount Textを更新していくようにしましょう。

PlayerControllerスクリプトを以下のように変更します。 修正している箇所には★マークをつけています。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI; // ★追加

public class PlayerController : MonoBehaviour
{
    public float speed;
    public Text countText;  // ★追加
    private int count;  // ★追加
    private Rigidbody rb;

    void Start ()
    {
        rb = GetComponent<Rigidbody>();
        count = 0;  // ★追加
        countText.text = "Count: 0"; // ★追加
    }

    void FixedUpdate ()
    {
    float moveHorizontal = Input.GetAxis("Horizontal");
    float moveVertical= Input.GetAxis("Vertical");

        Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
        rb.AddForce(movement * speed);
    }

    void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("Pick Up")) {
            other.gameObject.SetActive(false);
            count = count + 1;  // ★追加
            countText.text = "Count: " + count.ToString(); // ★追加
        }
    }
}

まず最初の修正箇所はこちらです。

using UnityEngine.UI; // ★追加

テキストなどのUIオブジェクトを使う場合、Unity標準のUIパッケージのインポートが必要です。

次はフィールドの追加です。 countTextは画面左上に表示するテキストを保持する変数です。 countはプレイヤーが取得したアイテムの数を保持する変数です。

    public Text countText;  // ★追加
    private int count;  // ★追加

次に、上記フィールドの初期化です。初期化に最適な場所はstartメソッドです。 countの初期値は当然0です。 countTextは、"Count: 0"という文字列で表示します。

        count = 0;  // ★追加
        countText.text = "Count: 0"; // ★追加

最後に、テキストを更新する処理を記載していきます。 プレイヤーがアイテムに触れて、アイテムを非アクティブにするのと同じタイミングでテキストを更新すればよさそうです。 countは現在の値に+1すればよいですね。 countTextは更新後のcountの値を使って作成します。

        if (other.gameObject.CompareTag("Pick Up")) {
            other.gameObject.SetActive(false);
            count = count + 1;  // ★追加
            countText.text = "Count: " + count.ToString(); // ★追加
        }

それでは、Unityに戻ってPlayerObjectをインスペクターで見てみましょう。 PlayerControllerの欄を見てください。Count Textというプロパティが追加されていますね。 これはcountTextフィールドをPublicで宣言したからです。 以前speedフィールドを作成した時と同じですね。
f:id:enia:20210303073902p:plain

speedと異なるのは、speedはint型のためインスペクターで直接値を設定することができます。 一方でcountTextに設定するのは「Count Textオブジェクトへの参照」です。 現状はCountTextが「なし」と表示されていますので、正しく参照を設定してあげましょう。

参照を設定するには、ヒエラルキービューで「Count Textオブジェクト」をドラッグし、Playerオブジェクトの「Count Textプロパティ」にドロップするだけです。

以下のように表示されればOKです。
f:id:enia:20210303073957p:plain

さあ、実際に動かして試してみましょう。 アイテムを取得するたびに、左上のカウントが更新されていきますね!
f:id:enia:20210303074211p:plain

NOTE:
参照を設定しなかったらどうなるでしょう?プレイモードにして動かしてみると、コンソールに以下のエラーがでました。

NullReferenceException: Object reference not set to an instance of an object PlayerController.Start () (at Assets/scripts/PlayerController.cs:19)

Unityのステータスバー(Unityの左下)にも赤字でエラーが表示されているのでうまく動かない場合は確認するようにしましょう。

全部アイテムを取得したらゲームクリアメッセージを出そう

最後に、アイテムを12個すべて取得したらゲームクリアメッセージを出すようにしてみましょう。 まずはTextオブジェクトをもう一つ追加します。名前は「Win Text」にしましょう。
f:id:enia:20210303074801p:plain

クリアで、ゲームの真ん中に表示された方が良いですね。 アンカープリセットはデフォルトで「middle-center」になっているはずです。 この状態で位置を(0, 0, 0)にすれば画面中央に文字が表示されます。
f:id:enia:20210303074848p:plain

あれ?ゲーム画面で見てみるとボールより左に寄ってますね。
f:id:enia:20210303075046p:plain

インスペクターの下の方に整列プロパティがあります。左揃えになっているので中央揃えに変更します。
f:id:enia:20210303075132p:plain

いい感じに中央に来ました。
f:id:enia:20210303075228p:plain

ではPlayerControllerスクリプトの方を修正していきます。 CountTextと同様にPublicなWinTextフィールドを追加しましょう。

    public Text winText;

次に、startメソッドでこのwinTextを初期化します。 クリアした時だけ表示される文字列なので、初期値は空文字にします。

    void Start ()
    {
        rb = GetComponent<Rigidbody>();
        count = 0;
        countText.text = "Count: 0";
        winText.text = ""; // ★追加
    }

最後に、OnTriggerEnterメソッドを修正してアイテムを集め終わったタイミングでwinTextを"You Win!"という文字列に更新します。 アイテム数は12個ですので、countが12以上になったらwinTextを更新すればよいですね。

    void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("Pick Up")) {
            other.gameObject.SetActive(false);
            count = count + 1;
            countText.text = "Count: " + count.ToString();
            if (count >= 12) { //★追加
                winText.text = "Your Win!";  //★追加
            } //★追加
        }
    }

Unityに戻ってインスペクターでWin Textフィールドに参照を設定しましょう。 f:id:enia:20210303080442p:plain

さぁ、実際に動かしてみましょう。 アイテムを全部取得したら”You Win!"という文字列が表示されますね! f:id:enia:20210303080713p:plain

玉転がしゲームへの機能追加は今回で最後となります。
次回はゲームをビルドしていきます。今回はここまで!