SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Godot Engine 2Dゲーム開発入門

【Godot Engine 2Dゲーム制作 Part4】UI部品を作成し、リストダイアログをつくろう

Godot Engine 2Dゲーム開発入門 第6回

レベルの管理と自動保存

レベルの管理と自動保存のスクリプトを作成

 ユーザーデータの保存と復帰はできました。今度は、「ListDialog」用に迷路のレベル選択メニューを作ったり、成績を管理したりします。

 data_manager.gdを、次のように書き換えます。

 _ready関数の「ファイルアクセスのテスト」はコメントアウトします。load_from_file関数とsave_to_file関数はそのままです。

data_manager.gd
extends Node

const PATH_SAVE_DATA = "user://save.dat"
var record_array = []
var level_array = []
var level_index = 0


func _ready() -> void:
	# ファイルアクセスのテスト
	#load_from_file()
	#record_array = [true, false, true]
	#save_to_file()
	#load_from_file()
	#DirAccess.remove_absolute(PATH_SAVE_DATA)

	# データの初期化と、保存データの復帰
	for i in 10:
		var h = 9 + i * 2
		var w = int(h * 1.5)
		level_array.append({"level": i + 1, "w": w, "h": h})
		record_array.append(false)
	load_from_file()


func get_level_menus() -> Array[Variant]:
	var menus = []
	for i in level_array.size():
		var item = level_array[i]
		var title = "レベル %s" % item["level"]
		if record_array[i]:
			title += "  クリア!"
		var desc = "迷路 横幅 {w}、高さ {h}".format(item)
		menus.append({"title": title, "desc": desc})
	return menus


func set_level(i: int) -> void:
	level_index = i


func get_current() -> Dictionary:
	return level_array[level_index]


func record() -> void:
	record_array[level_index] = true
	save_to_file()


func load_from_file() -> void:
	if FileAccess.file_exists(PATH_SAVE_DATA):
		var file = FileAccess.open(PATH_SAVE_DATA, FileAccess.READ)
		var json_string = file.get_as_text()
		var tmp_data = JSON.parse_string(json_string)
		if tmp_data != null:
			record_array = tmp_data
		print("record_array: " + str(record_array))
	else:
		print("Not exist.")


func save_to_file() -> void:
	var file = FileAccess.open(PATH_SAVE_DATA, FileAccess.WRITE)
	var json_string = JSON.stringify(record_array)
	file.store_string(json_string)

スクリプトの解説1 _ready

 新しく追加した部分を見ていきましょう。

 まずは_ready関数です。

data_manager.gd _ready
var level_array = []
var level_index = 0

func _ready() -> void:
	# データの初期化と、保存データの復帰
	for i in 10:
		var h = 9 + i * 2
		var w = int(h * 1.5)
		level_array.append({"level": i + 1, "w": w, "h": h})
		record_array.append(false)
	load_from_file()

 10レベル分のデータを作成しています。データの中身は「レベルの数値」と「迷路の横幅と高さ」、そして「初期の成績」です。

 また最後に、load_from_file関数で過去の成績を読み込んでいます。

 load_from_file関数では、データがまだない場合は読み込みをおこないません。そのためrecord_arrayは初期化した状態のままです。

 データがある場合は、読み込んだデータで置き換えられます。

スクリプトの解説2 get_level_menus

 次はget_level_menus関数です。

data_manager.gd get_level_menus
func get_level_menus() -> Array[Variant]:
	var menus = []
	for i in level_array.size():
		var item = level_array[i]
		var title = "レベル %s" % item["level"]
		if record_array[i]:
			title += "  クリア!"
		var desc = "迷路 横幅 {w}、高さ {h}".format(item)
		menus.append({"title": title, "desc": desc})
	return menus

 リストダイアログ用のメニューを作成して得ます。

 クリアしているレベルは" クリア!"の表記を加えます。

スクリプトの解説2 その他

 その他の細々とした関数です。

data_manager.gd set_level、get_current、record
func set_level(i: int) -> void:
	level_index = i


func get_current() -> Dictionary:
	return level_array[level_index]


func record() -> void:
	record_array[level_index] = true
	save_to_file()

 set_level関数は、ダイアログで選択したレベルを設定するための関数です。

 get_current関数は、現在のレベルの情報を得るための関数です。

 record関数は、迷路をクリアしたあと、そのレベルのクリアを記録する関数です。

ゲームへの組み込み

 それではこれらをゲームに組み込みましょう。

 まずはタイトル画面です。res://scn/title/title.gd_on_button_pressed関数を次のように書き換えます。

title.gd _on_button_pressed
func _on_button_pressed() -> void:
	var title = "迷路の選択"
	var menus = DataManager.get_level_menus()
	var res = await DialogList.open(title, menus)
	DataManager.set_level(res)

	# シーン変更
	SceneManager.load_scene(SceneManager.MAZE)

 レベルの選択ダイアログを出して、選択結果を設定します。

レベル選択ダイアログ
レベル選択ダイアログ

 次は、迷路画面です。res://scn/maze/maze.gd_ready関数を次のように書き換えます。

maze.gd _ready
func _ready() -> void:
	#MazeUtil.test_gen_maze()

	# シーン開始
	SceneManager.effect_enter_scene()
	BgmManager.start_bgm()

	# 迷路データの作成と表示
	var item = DataManager.get_current()
	var maze_info = MazeUtil.gen_maze(item["w"], item["h"])
	MazeLayout.layout(self, maze_info)

 DataManager.get_current関数で、タイトル画面で選択したレベルの情報を得ます。その横幅と高さで迷路を作成します。

選択レベルの横幅と高さを反映
選択レベルの横幅と高さを反映

 また、_on_goal_enter関数を次のように書き換えます。

maze.gd _on_goal_enter
# プレイヤーがゴールした
func _on_goal_enter(_area) -> void:
	DataManager.record()

	# プレイヤーを停止して、クリアシーンを追加
	player.is_act = false
	add_child(clear_scene.instantiate())

	# クリア音楽を流したあと、シーンを変更
	BgmManager.bgm_off()
	var audio = $AudioStreamPlayer
	audio.play()
	await get_tree().create_timer(audio.stream.get_length() + 1).timeout
	BgmManager.bgm_on()
	SceneManager.load_scene(SceneManager.TITLE)

 冒頭にDataManager.record()を追加しています。追加はこれだけです。

 ここでは、プレイしたレベルのクリア情報を保存します。

プレイヤーがゴールした
プレイヤーがゴールした

 ゲームの開発はこれで終了です。

次のページ
改良するならば

この記事は参考になりましたか?

Godot Engine 2Dゲーム開発入門連載記事一覧

もっと読む

この記事の著者

柳井 政和(ヤナイ マサカズ)

クロノス・クラウン合同会社 代表社員http://crocro.com/オンラインソフトを多数公開。プログラムを書いたり、ゲームを作ったり、記事を執筆したり、マンガを描いたり、小説を書いたりしています。「めもりーくりーなー」でオンラインソフト大賞に入賞。最近は、小説家デビューして小説も書いています(『裏切りのプログラム』他)。面白いことなら何でもOKのさすらいの企画屋です。 

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/21374 2025/08/07 11:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー