Skip to content

第10回 スコアを表示 ​

この回でつくるもの:画面の左上に「SCORE 000000」と表示し、敵を倒すたびに点数が増えるようにします。

この回で学ぶこと ​

  • Canvas と TextMeshPro で画面に文字を出す
  • Canvas Scaler と Rect Transform のアンカーで、画面の大きさが変わっても文字の位置がずれないようにする
  • ゲーム全体を管理する GameManager を作る
  • static(スタティック)で「どこからでも呼べる」ようにする
  • ToString("D6") で数字を6けたで表示する

前回までのふりかえり ​

第9回で、敵や自機がやられると爆発して音が鳴るようになりました。弾を撃つ音や BGM も流れています。 今回は、がんばって敵を倒した分だけ点数が増える「スコア」を作ります。

1. 画面に文字を出す ​

1-1. UI と Canvas について ​

スコアや残機のように、ゲームの世界ではなく画面にはりつけて表示するものを UI(ユーザーインターフェース)といいます。 Unity の UI は Canvas(キャンバス=画用紙)の上に置きます。Canvas の子にした文字やボタンだけが、画面に表示されます。

1-2. TextMeshPro の文字を作る ​

  1. Hierarchy の何もないところを右クリックし、UI > Text - TextMeshPro を選ぶ(メニューの GameObject > UI > Text - TextMeshPro でも同じ)
  2. 初めて使うときは TMP Importer というウィンドウが出るので、Import TMP Essentials を押す
  3. 読み込みが終わったら、TMP Importer ウィンドウを閉じる(Import TMP Examples & Extras は押さなくてよい)
  4. Hierarchy に Canvas、その子に Text (TMP)、そして EventSystem ができたのを確認する
  5. Text (TMP) の名前を ScoreText に変える

ヒント

TextMeshPro(テキストメッシュプロ)は、文字をきれいに表示するための Unity の仕組みです。Import TMP Essentials は、そのために必要なフォントなどをプロジェクトに入れるボタンで、1回押せば次からは出ません。

1-3. Canvas を見やすくする ​

Canvas は、ゲームの世界とくらべてとても大きく作られます。

  1. Hierarchy の Canvas をダブルクリックする(Scene ビューが Canvas 全体を映す)
  2. Scene ビューの上にある 2D ボタンを押すと、正面から見られて作業しやすい
  3. 作業が終わったら、もう一度 2D ボタンを押して元に戻す

ヒント

Scene ビューで Canvas がとても大きく見えても大丈夫です。Canvas は Game 画面にぴったり重なるように表示されます。UI は Game ビューで見た目を確認しましょう。

1-4. Canvas Scaler の設定 ​

画面の大きさがちがうパソコンで遊んでも、文字の大きさのバランスが変わらないようにします。

  1. Hierarchy で Canvas を選ぶ
  2. Inspector の Canvas Scaler コンポーネントで、UI Scale Mode を Scale With Screen Size にする
  3. Reference Resolution(基準の画面の大きさ)を X 1920、Y 1080 にする
  4. Screen Match Mode が Match Width Or Height になっていることを確認する
  5. Match を 0.5 にする

1-5. 文字を左上に固定する(アンカー) ​

アンカー(いかり)は、「UI を画面のどこを基準にして置くか」を決めるものです。左上にアンカーを置くと、画面の大きさが変わっても左上からの位置が変わりません。

  1. Hierarchy で ScoreText を選ぶ
  2. Inspector の Rect Transform の左上にある、四角いアイコン(アンカープリセット)をクリックする
  3. 表が出たら、Shift キーと Alt キー(Macは Shift と Option)を押しながら、左上(top-left) のマスをクリックする
  4. 文字が画面の左上の角にくっついたのを確認する
  5. Pos X を 40、Pos Y を -30 にする
  6. Width を 700、Height を 80 にする

ヒント

Shift はピボット(UI の中心点)も一緒に動かし、Alt は位置も一緒に動かすキーです。2つ押すと、角にぴったりくっつきます。 Pos Y がマイナスなのは、上の端から下へ 30 ずらすからです。

1-6. 文字の見た目を整える ​

  1. ScoreText の Inspector で、TextMeshPro - Text (UI) コンポーネントを見る
  2. Text Input の欄の文字を SCORE 000000 に書きかえる
  3. Font Size を 48 にする
  4. Vertex Color が白になっていることを確認する
  5. Alignment の左よせのボタンを押す
  6. Ctrl+S(Macは Cmd+S)でシーンを保存する

1-7. 動作確認 ​

Game ビューを見て、画面の左上に「SCORE 000000」と白い文字が出ていればOK。▶ を押しても同じように見えるか確かめましょう。

2. GameManager を作る ​

2-1. GameManager の役割 ​

スコアは、敵を倒したときに増やして、画面の文字も変えなければいけません。 いろいろな敵がバラバラにスコアを持つとややこしいので、ゲーム全体のことをまとめて管理する係を1つ作ります。これを GameManager(ゲームマネージャー)と呼びます。

2-2. static で「どこからでも呼べる」ようにする ​

敵が GameManager に「100点ふやして!」とお願いするには、敵が GameManager を見つけられないといけません。 そこで static(スタティック)を使います。

csharp
public static GameManager instance;

ふつうの変数は、オブジェクトひとつひとつが持つ「自分の持ち物」です。 static を付けた変数は、**クラスそのものが持つ「みんなの掲示板」**のようなものです。 GameManager は起動したとき(Awake)に、掲示板へ「GameManager はわたしです」と自分(this)を書きこみます。

csharp
void Awake()
{
    instance = this;
}

すると、どのスクリプトからでも GameManager.instance と書けば、その GameManager にたどりつけます。

csharp
GameManager.instance.AddScore(100);   // どこからでも呼べる!

先生へ

これはシングルトン(Singleton)と呼ばれる考え方の、いちばん簡単な形です。シーンに GameManager が2つあると後から Awake したほうで上書きされるので、「GameManager はシーンに1つだけ置く」とだけ伝えています。

2-3. GameManager スクリプトを書く ​

  1. Project で Assets/_Game/Scripts フォルダを開く
  2. 何もないところを右クリックし、Create > Scripting > MonoBehaviour Script を選ぶ
  3. 名前を GameManager にして Enter キーを押す
  4. ダブルクリックして開き、中身を全部消して次のように書く
csharp
using TMPro;
using UnityEngine;

// スコア・残機・ゲームの状態を管理する
public class GameManager : MonoBehaviour
{
    public static GameManager instance;   // どこからでも使えるようにする

    public int score = 0;
    public TextMeshProUGUI scoreText;

    void Awake()
    {
        instance = this;
    }

    void Start()
    {
        UpdateUI();
    }

    public void AddScore(int amount)
    {
        score += amount;
        UpdateUI();
    }

    void UpdateUI()
    {
        scoreText.text = "SCORE " + score.ToString("D6");
    }
}
  1. Ctrl+S(Macは Cmd+S)で保存する

ヒント

GameManager という名前のスクリプトは、Project ウィンドウで歯車のアイコンになります。これは Unity が特別あつかいしているだけで、ほかのスクリプトと同じように使えます。

コードの解説 ​

行意味
using TMPro;TextMeshPro を使うための1行。これがないと TextMeshProUGUI が使えない
public static GameManager instance;みんなの掲示板。ここに GameManager 自身を入れておく
public TextMeshProUGUI scoreText;画面の ScoreText を入れる箱。TextMeshProUGUI は「UI 用の TextMeshPro の文字」という型
void Awake()Start よりも先に呼ばれる関数。ほかのスクリプトが Start で GameManager を使っても間に合うように、ここで掲示板に書きこむ
public void AddScore(int amount)点数をふやす関数。public なのでほかのスクリプトから呼べる。amount はふやす量
score += amount;score = score + amount; と同じ意味
scoreText.text = ...画面の文字を書きかえる
score.ToString("D6")数字を6けたの文字にする(次の表)

ToString("D6") の「D」は10進数(ふつうの数)、「6」は6けたという意味です。足りないけたは 0 でうめます。

score の値score.ToString("D6")
0000000
100000100
12345012345

2-4. GameManager をシーンに置く ​

  1. Hierarchy の何もないところを右クリックし、Create Empty を選ぶ
  2. 名前を GameManager に変える
  3. Transform の Position を (0, 0, 0) にする(場所はどこでもよいが、そろえておく)
  4. Project の GameManager スクリプトを、Hierarchy の GameManager にドラッグする
  5. Inspector の Game Manager コンポーネントの Score Text の欄に、Hierarchy の ScoreText をドラッグする
  6. Ctrl+S(Macは Cmd+S)でシーンを保存する

3. 敵を倒したらスコアをふやす ​

3-1. Enemy に点数を追加する ​

Enemy を開いて、次のように書きかえます。

csharp
using UnityEngine;

// 敵の基本(移動・HP・やられたとき)
public class Enemy : MonoBehaviour
{
    public float speed = 3f;              // 左へ進む速さ
    public int hp = 1;                    // 体力(第8回)
    public GameObject explosionPrefab;    // 爆発(第9回)
    public AudioClip explosionSound;      // 爆発音(第9回)
    public int score = 100;               // 倒したときの点数(第10回) // ★追加

    bool isDead = false;

    void Update()
    {
        transform.Translate(Vector3.left * speed * Time.deltaTime, Space.World);

        // 画面の左に出たら消す
        if (transform.position.x < -12f)
        {
            Destroy(gameObject);
        }
    }

    // ダメージを受ける(第8回)
    public void TakeDamage(int damage)
    {
        if (isDead) return;

        hp -= damage;
        if (hp <= 0)
        {
            Die();
        }
    }

    void Die()
    {
        isDead = true;

        GameManager.instance.AddScore(score);   // ★追加

        if (explosionPrefab != null)
        {
            Instantiate(explosionPrefab, transform.position, Quaternion.identity);
        }
        if (explosionSound != null)
        {
            AudioSource.PlayClipAtPoint(explosionSound, Camera.main.transform.position);
        }

        Destroy(gameObject);
    }
}

保存します。

コードの解説 ​

行意味
public int score = 100;この敵を倒したときにもらえる点数。Inspector で敵ごとに変えられる
GameManager.instance.AddScore(score);掲示板から GameManager を見つけて、「score 点ふやして」とお願いする

ヒント

画面の左に出て消えたとき(Update の中の Destroy)は点数をふやしません。点数がふえるのは、弾で倒して Die() が呼ばれたときだけです。

3-2. 動作確認 ​

  1. Project の Enemy_Straight プレハブを選び、Enemy コンポーネントに Score が増えて 100 になっていることを確認する
  2. ▶ Play ボタンを押す
  3. 敵を1機倒すと「SCORE 000100」、2機倒すと「SCORE 000200」になればOK

よくあるまちがい

敵を倒した瞬間に NullReferenceException が出て止まる → シーンに GameManager オブジェクトを置き忘れているか、GameManager の Score Text が空っぽです。Console の赤いエラーをダブルクリックすると、どの行でエラーが出たかがわかります。

3-3. 文字の色や位置を調整する ​

  1. ▶ を止めてから、ScoreText を選ぶ
  2. Vertex Color で好きな色にしてみる
  3. Font Size や Pos X・Pos Y を変えて、見やすい位置にする
  4. Ctrl+S(Macは Cmd+S)でシーンを保存する

注意

▶ Play 中に変えたものは、Play を止めると元に戻ります。見た目の調整は Play を止めてからやりましょう。

4. 画面の大きさを変えて確かめる ​

アンカーと Canvas Scaler がちゃんと効いているか確かめましょう。

4-1. Game ビューの大きさを変える ​

  1. Game ビューの上にある、画面サイズのメニュー(Full HD (1920x1080) などと書いてあるところ)をクリックする
  2. 別の大きさ(例: 16:9 の小さいもの、または Free Aspect)を選ぶ
  3. スコアの文字が左上にくっついたまま、バランスよく表示されていればOK
  4. 確かめたら、元の 16:9(Full HD 1920x1080 など)に戻す

チャレンジ課題 ​

  • Enemy_Straight プレハブの Score を 250 にして、点数の増え方が変わるか確かめよう
  • 文字にフチどりを付けてみよう(ヒント: TextMeshPro の Material Preset の下、Outline にチェックを入れて Thickness を上げる)
  • ToString("D8") にすると何けたになるか試してみよう
  • 画面の右上に「STAGE 1」と表示してみよう(ヒント: アンカーを右上にする。Alignment は右よせ)

つまずきポイント ​

こんなときはここを確認
TextMeshProUGUI が赤い波線になるスクリプトの1行目に using TMPro; があるか
文字が出ないScoreText が Canvas の子になっているか。Vertex Color の透明度(A)が 0 になっていないか
文字が「SCORE 000000」のまま増えないGameManager の Score Text に ScoreText が入っているか。Enemy の Die に AddScore を書いたか
NullReferenceException が出るシーンに GameManager を置いて、スクリプトを付けたか
文字が途中で切れる・2行になるScoreText の Width を大きくするか、Font Size を小さくする
画面の大きさを変えると文字の位置がずれるアンカーが左上になっているか。Canvas Scaler が Scale With Screen Size か

まとめ ​

  • UI は Canvas の上に置き、文字は TextMeshPro で表示する
  • Canvas Scaler(Scale With Screen Size)とアンカーで、画面の大きさが変わっても位置とバランスが保たれる
  • static を付けた GameManager.instance は「みんなの掲示板」。どのスクリプトからでも GameManager を呼べる
  • ToString("D6") で 000100 のような6けた表示ができる