この記事はGPT先生と相談しながら書いています。
いろいろサンプルなどを見て参考にしていますが、ほとんどはいきなりゲーム画面から始まります。
ですが、ゲームと言ったらタイトル画面ですよね?
ということで、タイトル画面を作ってみることにしました。
ついでというか、画面遷移についても考えてみることに(主にGPT先生が)・・・
新規のプロジェクトを作成するときにテンプレとして使えないかと思ってます。
1.画面遷移図

超絶適当画面で恥ずかしいのですが、タイトル画面と設定画面、ゲーム画面を移動するだけのプロジェクトです。
Mainシーンは表示されませんが、各画面のロードと開放を行って制御しています。
2.ファイル構成
GameTemplate
+-- assets # 画像やサウンドなどのアセット
| +-- images
| +-- sounds
+-- scenes
| +-- main
| | +-- main.tscn # メインシーン
| | +-- main.gd # メインシーンに対応するスクリプト
| +-- menu
| | +-- title.tscn # タイトル画面
| | +-- title.gd # タイトル画面に対応するスクリプト
| | +-- settings.tscn # 設定画面
| | +-- settings.gd # 設定画面に対応するスクリプト
| +-- game # ゲームシーン
| +-- game_main.tscn # ゲームのメインシーン
| +-- game_main.gd # ゲームのメインシーンのスプリクト
| +-- ui
+-- scripts
+-- autoload
+-- global.gd # オートロード用のスクリプト
一応テンプレとして使いたいので、ファイル構成はまじめに考えました(先生が)笑
Mainシーンだけのフォルダとか要らなくね?とか思いましたが一応残すことにしました。
3.Mainシーン
extends Node2D
# mainシーン
# 実行時に呼び出されるシーン
# 今のところは、画面遷移を管理している
var _game_state = 0 # ゲームの状態(どの画面を表示しているか)
func _ready():
print("Main scene is ready.")
# ゲーム状態をタイトル画面に設定
change_state(Global.GameState.TITLE)
# 状態を変更する関数
func change_state(state: int):
# 現在の状態を更新
var current_state = state
# 既存の子ノードを全て削除
for child in get_children():
child.queue_free()
match current_state:
Global.GameState.TITLE:
load_title_scene()
Global.GameState.SETTINGS:
load_settings_scene()
Global.GameState.GAME:
load_game_scene()
_game_state = current_state
# タイトルシーンをロードする関数
func load_title_scene():
var title_scene = load("res://scenes/menu/title.tscn").instantiate()
add_child(title_scene)
title_scene.connect("start_game", Callable(self, "_on_start_game"))
title_scene.connect("open_settings", Callable(self, "_on_open_settings"))
# 中央に配置
title_scene.set_position(Vector2(get_viewport().size.x / 2, get_viewport().size.y / 2))
# 設定シーンをロードする関数
func load_settings_scene():
var settings_scene = load("res://scenes/menu/settings.tscn").instantiate()
add_child(settings_scene)
settings_scene.connect("back_to_title", Callable(self, "_on_back_to_title"))
# 中央に配置
settings_scene.set_position(Vector2(get_viewport().size.x / 2, get_viewport().size.y / 2))
# ゲームシーンをロードする関数
func load_game_scene():
var game_scene = load("res://scenes/game/game_main.tscn").instantiate()
add_child(game_scene)
# シグナルのコールバック関数
func _on_start_game():
change_state(Global.GameState.GAME)
func _on_open_settings():
change_state(Global.GameState.SETTINGS)
func _on_back_to_title():
change_state(Global.GameState.TITLE)
GDScript- func change_state(state: int)
- Mainシーンの子ノードをすべて開放する。
- 引数のステータスに合わせたシーンをロードする関数を実行する。
- func load_title_scene()
- タイトル画面シーンをロードする。
- Mainシーンの子ノードに追加する。
- タイトル画面シーン内で発行するシグナルを接続する。
- シーンの配置場所を設定
これをやらないとずれてしまいました。CenterContainerとかは自動で調整するのでは?と思いましたがずれるので入れています。
4.Settingsシーン
extends Control
# stttingsシーン
# ゲームの設定を行うシーン
# シグナルの定義
signal back_to_title
func _ready():
print("Settings scene is ready.")
func _on_BackButton_pressed():
emit_signal("back_to_title")
queue_free()
func _on_SaveButton_pressed():
print("Settings saved")
# ここに設定保存のロジックを追加
GDScriptここでは、ボタンが押されたらシグナルを発生させているだけです。
この記事を書いているときにふと思いましたが、ボタンのシグナルの接続を直接Mainシーンの関数に紐づければこのコードは要らないような気が・・・出来るかどうかはわかりませんが(笑
5.終わりに
ラベルとかボタンの配置にえらい苦労しましたが、仮のものなので割愛します。
すごい無駄な時間を過ごした気がします(笑
はじめは、Mainシーンに実際のゲームロジックを組み込む想定でした。
しかしMainシーンに貼り付けたラベルが表示されなく、その原因が全く分かりませんでした。
結局はchange_stateで子ノードをすべて解放していた為ラベルも消滅していたみたいです。
先生にやられた感がすさまじいです(笑
なのでゲームロジックも別のシーンで作ることにしました。
Mainシーンが画面遷移しかしていないのは、Mainとしてどうなの?とか思いモヤモヤしましたが
コード的には多分こっちの方がスッキリすると思ったので、この方法にしました。
ソースはGithubにアップロードしています。
すごい久々の投稿になりました。なかなかプログラムに向き合う気力が湧かなくて・・・
