はじめてのGodot 第7回: スコアを表示しよう — UIの基本
前回でゲームオーバーができました。今回は生存時間スコアを表示します。「よけゲー」がついに「スコアを競うゲーム」になります。
今回のゴール

- 画面上部に生存時間がリアルタイム表示される
- ゲームオーバー時に最終スコアが表示される
UIは「別のレイヤー」に置く — CanvasLayer
スコアやゲームオーバー表示のようなUI(画面表示)は、宇宙船や隕石のいる「ゲーム世界」とは別の場所に置くのが作法です。そのためのノードが CanvasLayer です。
CanvasLayerは「画面に直接貼り付くガラス板」だと思ってください。今作のカメラは動きませんが、たとえばマップをスクロールするゲームでは、ゲーム世界に直接置いたスコアは画面の外に流れて行ってしまいます。ガラス板に貼っておけば、世界がどれだけ動いてもスコアは画面の同じ場所に居続けます。今のうちに正しい作法で作っておきましょう。
HUDを組む
main.tscn で次のように組みます(HUD = ゲーム中の画面表示の通称です)。
Mainの子にCanvasLayerを追加し、名前をHUDにHUDの子にLabelを追加し、名前をScoreLabelに。画面の上部中央に配置し、フォントサイズを32くらいに- 前回作った
GameOverLabelをドラッグしてHUDの子に移動する
Main
├── Player
├── SpawnTimer
└── HUD (CanvasLayer)
├── ScoreLabel
└── GameOverLabel
%固有名 — 階層が変わっても壊れない参照
ここで困ったことがひとつ。GameOverLabel を移動したので、前回書いた $GameOverLabel という参照は壊れました(実行するとエラーになります)。$HUD/GameOverLabel に直してもいいのですが、また移動したらまた壊れます。
もっと良い方法があります。シーンドックで ScoreLabel と GameOverLabel をそれぞれ右クリックし、「固有名でアクセス」を選んでください。ノード名の横に % マークが付きます。こうしたノードは、どこに移動してもスクリプトから %名前 で参照できます。
スコアを実装する
main.gd を次のようにします。
extends Node2D
const METEOR_SCENE = preload("res://meteor.tscn")
var score = 0.0
var playing = true
func _ready():
$SpawnTimer.timeout.connect(_on_spawn_timer_timeout)
func _process(delta):
if playing:
score += delta
%ScoreLabel.text = "SCORE: %.1f" % score
func _on_spawn_timer_timeout():
var meteor = METEOR_SCENE.instantiate()
meteor.position = Vector2(randf_range(20, 460), -50)
meteor.speed = randf_range(200, 500)
add_child(meteor)
func _on_player_died():
playing = false
$SpawnTimer.stop()
%ScoreLabel.hide()
%GameOverLabel.text = "GAME OVER\nSCORE: %.1f" % score
%GameOverLabel.show()
実行してみてください。スコアが増えていき、当たると最終スコア付きでGAME OVERが出れば成功です。なお、ゲームオーバー時は最終スコアを中央にまとめて見せるので、上部の ScoreLabel は %ScoreLabel.hide() で隠しています(同じスコアが2か所に出るのを防ぐため)。
新しいことを整理
生存時間 = deltaの積み立て
score += delta
delta は「前のフレームからの経過時間」でした。毎フレーム足し込めば、合計が経過秒数そのものになります。第2回で学んだdeltaの、見事な再利用です。
playing フラグ — 状態を変数で持つ
var playing = true は「ゲーム進行中か?」を覚えておく変数です(こういう真/偽の変数をフラグと呼びます)。死んだら false にして、if playing: でスコア加算を止めています。「今ゲームはどういう状態か」を変数で持つ — これはどんなゲームにも出てくる基本パターンです。
文字列と % フォーマット
%ScoreLabel.text = "SCORE: %.1f" % score
"..." で囲んだものが文字列(文字のデータ)です。Labelの text に文字列を入れると画面に表示されます。
"%.1f" % score は「scoreを小数1桁の文字にして埋め込む」という書き方です。score は 12.3456789... のような細かい数なので、そのまま表示すると桁が暴れて読めません。%.1f で 12.3 に整えています。
\n は改行を意味する特別な文字です。
日本語を表示したい場合
Textに日本語を入れると、デフォルトフォントでも一応表示されますが、ゲームの雰囲気に合うフォントを使いたくなったら、フォントファイル(.ttf)をプロジェクトにドラッグ&ドロップして、LabelのTheme Overrides→Fontsに設定します。Google Fontsに商用可の日本語フォントがたくさんあります。
つまずきポイント
Node not found: "GameOverLabel": HUDに移動したのに$GameOverLabelのままになっている箇所が残っています。%GameOverLabelに置き換えてください(固有名の設定も忘れずに)- スコアの数字がすごい桁で表示される:
%.1fの書き忘れです - スコアが画面に出ない: ScoreLabelが画面外にいないか、HUDの子になっているか確認してください
今回学んだこと
- UIは
CanvasLayer(画面に貼り付くガラス板)に置く %固有名を使うと、ノードを移動しても参照が壊れないdeltaを毎フレーム足すと経過時間になる- 状態は
playingのようなフラグ変数で持つ - 文字列
"..."と%フォーマットで数値を表示用に整える
次回予告
いよいよ最終回。音とリスタートを付けて、何度でも遊べる「完成品」に仕上げます。