Developer

さくさく理解する Godot 入門(ただし2Dに限る)応用編 シーズン2(数独パズル)【第8回】
2021.11.29
Lv1

さくさく理解する Godot 入門(ただし2Dに限る)応用編 シーズン2(数独パズル)【第8回】

目次

  • レベル画面
  • 問題ボタン
  • レベル画面作成
  • レベル画面スクリプト
  • さいごに

レベル画面

パズルを解くメイン画面はほぼ出来上がったので、次に問題を選択するレベル画面を実装する。
実装手順は、まず画面を作成し、それにスクリプトをアタッチし、動作を実装するといういつもの段取りだ。

なのだが、問題ボタンには問題をサムネイル表示したいので、まずはそのためのシーン作成から始める。

■問題ボタン

新規シーンを作成し、ルートノードを TextureButton とし、「QuestButton」にリネームする。

以下のスクリプトをアタッチする。

const CELL_WIDTH = 7
const CELL_SPC = 1
const BUTTON_WIDTH = CELL_WIDTH*9 + CELL_SPC*10

var down = false
var quest = "008010240 090320061 102805007 039452700 670103092 001679380 900706108 780091020 015030600"

func _ready():
    pass # Replace with function body.

func _draw():
    quest = quest.replace(" ", "")
    var col = Color("#f0f0f0") if !down else Color("#f0f080")
    draw_rect(Rect2(0, 0, BUTTON_WIDTH, BUTTON_WIDTH), col)
    for y in range(9):
        var py = y * (CELL_WIDTH+CELL_SPC) + CELL_SPC
        for x in range(9):
            if quest[y*9+x] >= "1" && quest[y*9+x] <= "9":
                var px = x * (CELL_WIDTH+CELL_SPC) + CELL_SPC
                draw_rect(Rect2(px, py, CELL_WIDTH, CELL_WIDTH), Color("#808080"))


func set_quest(q):
    quest = q
    update()

このシーンでは _draw() を再実装し、問題のサムネイルを自前で表示している。
F6 で単独実行したときに、何も表示されないのは嫌なので、デフォルト問題を用意し、それを表示している。
また、set_quest(q) という関数を用意しておく。

以上を F6 で実行すると、下図のように問題がサムネイル表示されるはずだ。

インスペクタでノードを選び、button_dows(), button_up() シグナルを自分自身にコネクトする。
ハンドラの内容は以下の通り。down 変数を true/false に設定し、update() をコールして、自分自身を強制的に再描画する。

func _on_QuestButton_button_down():
    down = true;
    update()
    
func _on_QuestButton_button_up():
    down = false;
    update()

■レベル画面作成

問題ボタンの用意ができたので、今度こそレベル画面を作成する。

新規シーンを作成し、ルートノードを Node2D とし、「LevelScene」にリネームする。

メイン画面同様に、ColorRect の背景を設置し、色・サイズを設定する。

メイン画面では、削除数字落下処理の時に別シーンをスクリプトで動的に追加する例を見たが、 ここではエディタで別シーンを手動で追加する方法を示す。

先に作成した問題ボタンシーンをファイルシステムからドラッグし、ノードツリーの HBoxContainer にドロップして、画面に追加

追加したノードの「QuestButton」を「QuestButton1」にリネームした後に、Ctrl + D を4回押して複製を行い、ボタンを5つに増やす。

この時点で F6 を押してシーンを実行すると下図のようにサムネイル付き問題ボタンが5個表示される。

タイトル・バージョン番号のためのラベルを設置する。ラベルはTTFフォントを指定する。 その具体的方法はこのシリーズの最初の方で説明してるので、忘れた場合は読み直して欲しい。

■レベル画面スクリプト

ルートノードの「LevelScene」にスクリプトをアタッチしておき、問題ボタン1を選び、インスペクタのノードタブで pressed() をダブルクリックし、アタッチしたスクリプトに接続する。

下記にレベル画面のスクリプトを示す。

func _ready():
    #print(Global.quest)
    $CenterContainer/HBoxContainer/questButton1.set_quest(Global.quest[0])
    $CenterContainer/HBoxContainer/questButton2.set_quest(Global.quest[1])
    $CenterContainer/HBoxContainer/questButton3.set_quest(Global.quest[2])
    $CenterContainer/HBoxContainer/questButton4.set_quest(Global.quest[3])
    $CenterContainer/HBoxContainer/questButton5.set_quest(Global.quest[4])
    pass # Replace with function body.

func to_main(n):
    Global.qNumber = n
    get_tree().change_scene("res://MainScene.tscn")
func _on_questButton1_pressed():
    to_main(1)
func _on_questButton2_pressed():
    to_main(2)
func _on_questButton3_pressed():
    to_main(3)
func _on_questButton4_pressed():
    to_main(4)
func _on_questButton5_pressed():
    to_main(5)

_ready() では初期化処理として、各ボタンへ実際の問題を設定し、問題のサムネイルを表示可能にする。

to_main(n) 関数は、問題番号をグローバル変数に設定し、シーンを MainScene に切り替える(遷移する)。 「get_tree().change_scene(“res://MainScene.tscn”)」と記述するとシーンを切り替えることが出来る。

_on_numButton1_pressed() ~ _on_questButton5_pressed() は各問題バタンが押されたときにコールされるハンドラで、 それ自信の番号を実引数にして to_main(n) を呼んでいるだけだ。

上記スクリプトをアタッチ後に、アプリを実行すると下図のようになる。各ボタンにそれぞれの問題が表示されるはずだ。 そして、問題ボタンをクリックするとメイン画面に遷移する。

レベル画面で選択された問題を表示するには、メインシーンのスクリプトを下記のように一部修正する。

func _ready():
    .....
    set_quest(Global.quest[Global.qNumber-1])
    #set_quest("008010240090320061102805007039452700 670103092 001679380 900706108 780091020 015030600")
    .....

また、左上の戻るボタンが押された場合の処理を実装していなかったので、ボタン押下時のシグナルをコネクトし、 以下のようにコードを実装する。

func _on_backButton_pressed():
    get_tree().change_scene("res://LevelScene.tscn")

さいごに

本シリーズでは、Godot を使用し、数独パズルをユーザが解くアプリを実装する具体的な方法を解説した。 流れとしては、必要なシーン(画面)を作り、それらにスクリプトをアタッチすることで、動作を実装するという形式だ。

アプリをさくさく実装できるようになるには、Godot にどのようなクラスがあり、それをどう使えばいいかという知識が必要になる。 それらをすべてあらかじめ勉強し、習熟するのは並大抵のことではなく、多くの人は途中で挫折しがちだ。

なので、なるべく小さなアプリを実際に作成してみて、そのとき必要なクラスを勉強し、使いこなしていくようにすれば、 比較的簡単なのではないかと考える。

今回示したアプリは、規模も小さく、またアニメーション的な動きもほとんどないので、筆者には楽に作成することができたし、 読者が細部まで理解するのも比較的容易なのではないかと考える。

最初は大変かもしれないが、ぜひ細部まで理解し、Godot でのアプリ開発スキルを身に着けていただけると幸いだ。