ダークモード
第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 の文字を作る
- Hierarchy の何もないところを右クリックし、UI > Text - TextMeshPro を選ぶ(メニューの GameObject > UI > Text - TextMeshPro でも同じ)
- 初めて使うときは TMP Importer というウィンドウが出るので、Import TMP Essentials を押す
- 読み込みが終わったら、TMP Importer ウィンドウを閉じる(Import TMP Examples & Extras は押さなくてよい)
- Hierarchy に
Canvas、その子にText (TMP)、そしてEventSystemができたのを確認する Text (TMP)の名前をScoreTextに変える
ヒント
TextMeshPro(テキストメッシュプロ)は、文字をきれいに表示するための Unity の仕組みです。Import TMP Essentials は、そのために必要なフォントなどをプロジェクトに入れるボタンで、1回押せば次からは出ません。
1-3. Canvas を見やすくする
Canvas は、ゲームの世界とくらべてとても大きく作られます。
- Hierarchy の
Canvasをダブルクリックする(Scene ビューが Canvas 全体を映す) - Scene ビューの上にある 2D ボタンを押すと、正面から見られて作業しやすい
- 作業が終わったら、もう一度 2D ボタンを押して元に戻す
ヒント
Scene ビューで Canvas がとても大きく見えても大丈夫です。Canvas は Game 画面にぴったり重なるように表示されます。UI は Game ビューで見た目を確認しましょう。
1-4. Canvas Scaler の設定
画面の大きさがちがうパソコンで遊んでも、文字の大きさのバランスが変わらないようにします。
- Hierarchy で
Canvasを選ぶ - Inspector の Canvas Scaler コンポーネントで、UI Scale Mode を Scale With Screen Size にする
- Reference Resolution(基準の画面の大きさ)を X
1920、Y1080にする - Screen Match Mode が Match Width Or Height になっていることを確認する
- Match を
0.5にする
1-5. 文字を左上に固定する(アンカー)
アンカー(いかり)は、「UI を画面のどこを基準にして置くか」を決めるものです。左上にアンカーを置くと、画面の大きさが変わっても左上からの位置が変わりません。
- Hierarchy で
ScoreTextを選ぶ - Inspector の Rect Transform の左上にある、四角いアイコン(アンカープリセット)をクリックする
- 表が出たら、Shift キーと Alt キー(Macは Shift と Option)を押しながら、左上(top-left) のマスをクリックする
- 文字が画面の左上の角にくっついたのを確認する
- Pos X を
40、Pos Y を-30にする - Width を
700、Height を80にする
ヒント
Shift はピボット(UI の中心点)も一緒に動かし、Alt は位置も一緒に動かすキーです。2つ押すと、角にぴったりくっつきます。 Pos Y がマイナスなのは、上の端から下へ 30 ずらすからです。
1-6. 文字の見た目を整える
ScoreTextの Inspector で、TextMeshPro - Text (UI) コンポーネントを見る- Text Input の欄の文字を
SCORE 000000に書きかえる - Font Size を
48にする - Vertex Color が白になっていることを確認する
- Alignment の左よせのボタンを押す
- 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 スクリプトを書く
- Project で
Assets/_Game/Scriptsフォルダを開く - 何もないところを右クリックし、Create > Scripting > MonoBehaviour Script を選ぶ
- 名前を
GameManagerにして Enter キーを押す - ダブルクリックして開き、中身を全部消して次のように書く
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");
}
}- 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") |
|---|---|
| 0 | 000000 |
| 100 | 000100 |
| 12345 | 012345 |
2-4. GameManager をシーンに置く
- Hierarchy の何もないところを右クリックし、Create Empty を選ぶ
- 名前を
GameManagerに変える - Transform の Position を (0, 0, 0) にする(場所はどこでもよいが、そろえておく)
- Project の
GameManagerスクリプトを、Hierarchy のGameManagerにドラッグする - Inspector の Game Manager コンポーネントの Score Text の欄に、Hierarchy の
ScoreTextをドラッグする - 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. 動作確認
- Project の
Enemy_Straightプレハブを選び、Enemy コンポーネントに Score が増えて100になっていることを確認する - ▶ Play ボタンを押す
- 敵を1機倒すと「SCORE 000100」、2機倒すと「SCORE 000200」になればOK
よくあるまちがい
敵を倒した瞬間に NullReferenceException が出て止まる → シーンに GameManager オブジェクトを置き忘れているか、GameManager の Score Text が空っぽです。Console の赤いエラーをダブルクリックすると、どの行でエラーが出たかがわかります。
3-3. 文字の色や位置を調整する
- ▶ を止めてから、
ScoreTextを選ぶ - Vertex Color で好きな色にしてみる
- Font Size や Pos X・Pos Y を変えて、見やすい位置にする
- Ctrl+S(Macは Cmd+S)でシーンを保存する
注意
▶ Play 中に変えたものは、Play を止めると元に戻ります。見た目の調整は Play を止めてからやりましょう。
4. 画面の大きさを変えて確かめる
アンカーと Canvas Scaler がちゃんと効いているか確かめましょう。
4-1. Game ビューの大きさを変える
- Game ビューの上にある、画面サイズのメニュー(
Full HD (1920x1080)などと書いてあるところ)をクリックする - 別の大きさ(例: 16:9 の小さいもの、または Free Aspect)を選ぶ
- スコアの文字が左上にくっついたまま、バランスよく表示されていればOK
- 確かめたら、元の 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けた表示ができる