
キャラクターセレクト画面を作ろう
これまで作ってきたジャンケンゲームを例に、キャラクターセレクト画面を作ってみます。
アドバイザーは、ChatGPTとGemini2.0です。
今日のハイライト

キャラクターセレクト画面
ボタン式のセレクト画面
AIに一番簡単なキャラクターセレクト画面について聞いてみると、Button式を勧められたので、それで作ってみます。
フローのススメ
セレクト画面などの画面遷移はフローを書くと後で挙動をチェックできて良いので簡単でも書いた方が良いです。

CharacterSelectシーン
・画面にボタンを並べてキャラクター名をつける
・ボタンの子ノードに画像を設置
・選択したキャラ名をNPC1とNPC2に表示
・「スタート」と「キャンセル」ボタンを配置

Global変数を追加
キャラクターセレクト用の変数をGlobalシーンに追加します。
# キャラクターセレクト用
var npc_1p = null
var npc_2p = null
CharacterSelectシーンにスクリプトを追加
初期設定
・遷移先のMainシーンの場所を設定
・セレクト画面用の変数を設定
・スタートボタンを隠す
・勝敗データの初期化(※ゲーム画面に遷移してからでも良い)
extends Control
# 遷移先のMainシーンの場所
var main = preload("res://Main.tscn")
# キャラクター配列
var npc1 = null # 1Pのキャラ名
var npc2 = null # 2Pのキャラ名
var character = null # 押されたボタンのノード名
var button_name = null # ボタンのキャラ名を登録
var selected = false # 1Pと2Pが両方とも選択されたかフラグ
func _ready():
$NPC1Label.text = "1P: 未決定" # NPC1Labelの初期設定
$NPC2Label.text = "2P: 未決定" # NPC2Labelの初期設定
$TitleLabel.text = "キャラクターセレクト" # セレクト画面のタイトル
$StartButton.hide()
#勝敗データを初期化
Global.p_win = 0
Global.c_win = 0
Global.total = 0
blink_message() # メッセージを表示
メッセージの表示
・キャラ選択用のメッセージを点滅表示
func blink_message():
if not selected:
$Message.show()
$Message.text = "1Pと2Pを設定してください!"
await get_tree().create_timer(1.0).timeout
$Message.hide()
await get_tree().create_timer(1.0).timeout
blink_message()
1Pと2Pにキャラを設定
・1Pキャラが未選択の場合にボタンが押されたら、1Pにキャラを設定
・2Pキャラが未選択の場合にボタンが押されたら、2Pにキャラを設定
・両方にキャラが設定されている状態では何もしない
# ボタンを押して1Pと2Pにキャラを設定
func _on_character_selected(character):
if npc1 == null:
npc1 = button_name
Global.npc_1p = character
$NPC1Label.text = "1P: " + npc1 # Labelのテキストを更新
print("NPC1: ", Global.npc_1p)
elif npc2 == null:
npc2 = button_name
Global.npc_2p = character
$NPC2Label.text = "2P: " + npc2 # Labelのテキストを更新
print("NPC2: " + Global.npc_2p)
selected = true
selected_message()
else:
print("すでにNPC1とNPC2が選択されています。")
スタートメッセージ
・1Pと2P両方のキャラが選択されたらスタートボタンを表示
・メッセージも変化
# 1Pと2Pのキャラが選択されたら、「スタート!」を表示
func selected_message():
if selected:
$StartButton.show()
$Message.show()
$Message.text = "スタート!"
await get_tree().create_timer(1.0).timeout
$Message.hide()
await get_tree().create_timer(1.0).timeout
selected_message()
ボタンをCharacterSelectのスクリプトに接続
・各キャラボタンのノードのシグナル「pressed()」をスクリプトに接続
・スタートボタンや戻るボタンも接続
キャラのボタンの接続スクリプト
キャラのボタンが押された時に発生するシグナルで発動する関数を設定していきます。全てのキャラボタンで同じなので、ここではサンプルのスクリプトだけ記載します。
・characterで遷移先のキャラのノード名を登録
・button.nameにボタンのテキスト名(キャラ名)を登録
・_on_character_selectedに値を返す
func _on_boy_pressed() -> void:
character = "Boy"
button_name = $Boy.text
_on_character_selected(character)
スタートボタンの接続スクリプト
・スタートボタンが押されたらゲームを開始(Mainシーンへ遷移)
# スタートボタンを押してゲーム画面へ遷移
func _on_start_button_pressed() -> void:
if selected:
get_tree().change_scene_to_file(main.resource_path)
キャンセルボタンの接続スクリプト
・キャンセルボタンが押されたら情報を初期化しスタートボタンを非表示
・キャンセルメッセージを表示
func _on_cancel_button_pressed():
npc1 = null
npc2 = null
selected = false
$NPC1Label.text = "1P: 未決定" # Labelのテキストをクリア
$NPC2Label.text = "2P: 未決定" # Labelのテキストをクリア
$StartButton.hide()
$Message.show()
$Message.text = "選択がキャンセルされました!"
await get_tree().create_timer(1.0).timeout
print("選択がキャンセルされました。")
blink_message()
ゲームにつなげる
参考例として、これまで作ってきたジャンケンゲームに選択したゲームのデータを引き継ぎます。
Characterシーンの修正
キャラクターセレクト画面で選択したキャラをCharacterシーンに受け渡しするための修正をします。
初期設定
・charパスは必要ないので削除
・子ノードを取得するため、characterシーンのノードを設定
extends Node
# 親ノード
@onready var main = get_node("../")
@onready var npc = $"."
# 1p,2pのパス
@onready var name1 = $"HUD/1PName"
@onready var name2 = $"HUD/2PName"
@onready var hand1 = $"HUD/1PHand"
@onready var hand2 = $"HUD/2PHand"
var selected_1p = false
var selected_2p = false
var p1 = null
var p2 = null
キャラを設定
・キャラセレで選択したキャラをGlobal変数で引継ぎ、ノードのパスを取得
・1Pと2Pのキャラを表示
# キャラ選択
func _ready() -> void:
# 1Pと2Pのキャラ選択
p1 = npc.get_node_or_null(Global.npc_1p)
p2 = npc.get_node_or_null(Global.npc_2p)
if Global.npc_1p == "Human":
Global.ai_on = false
else:
Global.ai_on = true
# 1pと2pのキャラ表示
p1.show()
p1.position = Vector2(90,150)
p2.show()
p2.position = Vector2(550,150)
name1.text = "1P:" + Global.p1.chr_name
name2.text = "2P:" + Global.p2.chr_name
キャラクターを選択してゲームスタート
キャラ選択してキャンセル、もう一度キャラを選択してスタートで、無事ゲームが起動しました。良かった。

次はジャンケン最強リーグ戦かな?
スタート画面やリセットとか選択画面へ戻るもつけたいな。
やりたいことは増すばかり。。。寄り道できるのもインディーの醍醐味です。無計画って、すっげー楽しい!!!
誰かの参考になれば幸いです。