ふりかえり
前回はセーブ機能の第一歩として、ゴールド(G)とダイヤのデータを保存・読み込みできるようにしました。今回はその続きです!
セーブ機能を実装!②
今回はゲーム内のさまざまなデータも含めて、完全なセーブ機能を実装していきます!
対象は以下の通りです:
- プレイヤーのステータス
- 戦闘状況(HPやスキルのクールタイム)
- ステージの進行度
- 強化状態
- 所持アーティファクト
- 音量設定(SE/BGM)
スクリプトの変更
SaveManager.cs
アーティファクトのセーブとロード
アーティファクトの数とそれぞれの情報(名前、説明、効果、ランク、レベルなど)を保存。読み込み時にはそれらを復元し、効果も適用します。
スキルの状態保存
各スキルのレベル、解放状態、クールタイムなどをセーブ&ロードします。
ステージ進行度
現在のステージ番号と、そのステージで倒したモンスターの数を記録します。
プレイヤーと敵のHP情報
バトル中にゲームを中断しても、次回起動時にその状態から再開できるようにHPを保存。
敵データの保存
敵の名前、ステータス、画像サイズなどを保存・復元します。バトル中の敵の状態が完全に復元されます。
音量設定
SEとBGMの音量設定も保存しておくことで、次回起動時も前回の音量で再生されます。
// アーティファクトデータをセーブ
private void SaveArtifactData()
{
try
{
// 所持アーティファクトの数を保存
ES3.Save("OwnedArtifactsCount", artifactManager.ownedArtifacts.Count, saveFileName);
// 各アーティファクトのデータを保存
for (int i = 0; i < artifactManager.ownedArtifacts.Count; i++)
{
var artifact = artifactManager.ownedArtifacts[i];
string prefix = $"Artifact_{i}_";
ES3.Save(prefix + "Name", artifact.name, saveFileName);
ES3.Save(prefix + "Description", artifact.description, saveFileName);
ES3.Save(prefix + "Type", artifact.artifactType, saveFileName);
ES3.Save(prefix + "BaseValue", artifact.baseValue, saveFileName);
ES3.Save(prefix + "ValuePerLevel", artifact.valuePerLevel, saveFileName);
ES3.Save(prefix + "Level", artifact.level, saveFileName);
ES3.Save(prefix + "Rank", artifact.rank, saveFileName);
}
Debug.Log("アーティファクトデータをセーブしました");
}
catch (System.Exception e)
{
Debug.LogError($"アーティファクトセーブエラー: {e.Message}");
}
}
// アーティファクトデータをロード
private void LoadArtifactData()
{
try
{
// 所持アーティファクトの数をロード
if (ES3.KeyExists("OwnedArtifactsCount", saveFileName))
{
int count = ES3.Load<int>("OwnedArtifactsCount", saveFileName);
artifactManager.ownedArtifacts.Clear();
// 各アーティファクトのデータをロード
for (int i = 0; i < count; i++)
{
string prefix = $"Artifact_{i}_";
if (ES3.KeyExists(prefix + "Name", saveFileName))
{
ArtifactData artifact = new ArtifactData
{
name = ES3.Load<string>(prefix + "Name", saveFileName),
description = ES3.Load<string>(prefix + "Description", saveFileName),
artifactType = ES3.Load<ArtifactType>(prefix + "Type", saveFileName),
baseValue = ES3.Load<float>(prefix + "BaseValue", saveFileName),
valuePerLevel = ES3.Load<float>(prefix + "ValuePerLevel", saveFileName),
level = ES3.Load<int>(prefix + "Level", saveFileName),
rank = ES3.Load<ArtifactRank>(prefix + "Rank", saveFileName)
};
artifactManager.ownedArtifacts.Add(artifact);
}
}
// アーティファクト効果を適用
artifactManager.ApplyAllArtifactEffects();
Debug.Log($"アーティファクトデータをロードしました: {count}個");
}
}
catch (System.Exception e)
{
Debug.LogError($"アーティファクトロードエラー: {e.Message}");
}
}
// スキルデータをセーブ
private void SaveSkillData()
{
try
{
// 各スキルのレベルとクールタイムを保存
for (int i = 0; i < skillManager.skills.Count; i++)
{
var skill = skillManager.skills[i];
string prefix = $"Skill_{i}_";
ES3.Save(prefix + "Level", skill.skillLevel, saveFileName);
ES3.Save(prefix + "IsUnlocked", skill.isUnlocked, saveFileName);
ES3.Save(prefix + "CurrentCooldown", skill.currentCooldown, saveFileName);
}
Debug.Log("スキルデータをセーブしました");
}
catch (System.Exception e)
{
Debug.LogError($"スキルセーブエラー: {e.Message}");
}
}
// スキルデータをロード
private void LoadSkillData()
{
try
{
// 各スキルのレベルとクールタイムをロード
for (int i = 0; i < skillManager.skills.Count; i++)
{
string prefix = $"Skill_{i}_";
if (ES3.KeyExists(prefix + "Level", saveFileName))
{
skillManager.skills[i].skillLevel = ES3.Load<int>(prefix + "Level", saveFileName);
}
if (ES3.KeyExists(prefix + "IsUnlocked", saveFileName))
{
skillManager.skills[i].isUnlocked = ES3.Load<bool>(prefix + "IsUnlocked", saveFileName);
}
if (ES3.KeyExists(prefix + "CurrentCooldown", saveFileName))
{
skillManager.skills[i].currentCooldown = ES3.Load<int>(prefix + "CurrentCooldown", saveFileName);
}
}
Debug.Log("スキルデータをロードしました");
}
catch (System.Exception e)
{
Debug.LogError($"スキルロードエラー: {e.Message}");
}
}
// 音量設定をセーブ
private void SaveAudioSettings()
{
try
{
ES3.Save("SEVolume", audioManager.seVolume, saveFileName);
ES3.Save("BGMVolume", audioManager.bgmVolume, saveFileName);
Debug.Log("音量設定をセーブしました");
}
catch (System.Exception e)
{
Debug.LogError($"音量設定セーブエラー: {e.Message}");
}
}
// 音量設定をロード
private void LoadAudioSettings()
{
try
{
if (ES3.KeyExists("SEVolume", saveFileName))
{
audioManager.seVolume = ES3.Load<float>("SEVolume", saveFileName);
audioManager.SetSEVolume(audioManager.seVolume);
}
if (ES3.KeyExists("BGMVolume", saveFileName))
{
audioManager.bgmVolume = ES3.Load<float>("BGMVolume", saveFileName);
audioManager.SetBGMVolume(audioManager.bgmVolume);
}
Debug.Log("音量設定をロードしました");
}
catch (System.Exception e)
{
Debug.LogError($"音量設定ロードエラー: {e.Message}");
}
}
// ステージ進行度をセーブ
private void SaveStageProgress()
{
try
{
ES3.Save("CurrentStage", stageManager.GetCurrentStage(), saveFileName);
ES3.Save("MonstersDefeatedInStage", stageManager.GetMonstersDefeatedInStage(), saveFileName);
Debug.Log("ステージ進行度をセーブしました");
}
catch (System.Exception e)
{
Debug.LogError($"ステージ進行度セーブエラー: {e.Message}");
}
}
// ステージ進行度をロード
private void LoadStageProgress()
{
try
{
int currentStage = 1;
int monstersDefeated = 0;
if (ES3.KeyExists("CurrentStage", saveFileName))
{
currentStage = ES3.Load<int>("CurrentStage", saveFileName);
Debug.Log($"セーブデータからステージをロード: {currentStage}");
}
if (ES3.KeyExists("MonstersDefeatedInStage", saveFileName))
{
monstersDefeated = ES3.Load<int>("MonstersDefeatedInStage", saveFileName);
Debug.Log($"セーブデータから敵撃破数をロード: {monstersDefeated}");
}
// StageManagerにステージ進行度を設定
stageManager.SetStageProgress(currentStage, monstersDefeated);
Debug.Log("ステージ進行度をロードしました");
}
catch (System.Exception e)
{
Debug.LogError($"ステージ進行度ロードエラー: {e.Message}");
}
}
// プレイヤーの現在HPをセーブ
private void SavePlayerCurrentHP()
{
try
{
ES3.Save("PlayerCurrentHP", playerManager.player.currentHP, saveFileName);
Debug.Log($"プレイヤーの現在HPをセーブ: {playerManager.player.currentHP}");
}
catch (System.Exception e)
{
Debug.LogError($"プレイヤーの現在HPセーブエラー: {e.Message}");
}
}
// プレイヤーの現在HPをロード
private void LoadPlayerCurrentHP()
{
try
{
if (ES3.KeyExists("PlayerCurrentHP", saveFileName))
{
playerManager.player.currentHP = ES3.Load<int>("PlayerCurrentHP", saveFileName);
Debug.Log($"セーブデータからプレイヤーの現在HPをロード: {playerManager.player.currentHP}");
}
}
catch (System.Exception e)
{
Debug.LogError($"プレイヤーの現在HPロードエラー: {e.Message}");
}
}
// 敵の情報をセーブ
private void SaveEnemyData()
{
try
{
if (enemyManager.enemy != null)
{
ES3.Save("EnemyName", enemyManager.enemy.name, saveFileName);
ES3.Save("EnemyLevel", enemyManager.enemy.level, saveFileName);
ES3.Save("EnemyCurrentHP", enemyManager.enemy.currentHP, saveFileName);
ES3.Save("EnemyMaxHP", enemyManager.enemy.maxHP, saveFileName);
ES3.Save("EnemyAttack", enemyManager.enemy.attack, saveFileName);
ES3.Save("EnemyDefense", enemyManager.enemy.defense, saveFileName);
ES3.Save("EnemyExpReward", enemyManager.enemy.expReward, saveFileName);
ES3.Save("EnemyGoldReward", enemyManager.enemy.goldReward, saveFileName);
ES3.Save("EnemyCriticalRate", enemyManager.enemy.criticalRate, saveFileName);
ES3.Save("EnemyCriticalDamageMultiplier", enemyManager.enemy.criticalDamageMultiplier, saveFileName);
// 敵のサイズ情報をセーブ
if (enemyManager.enemyUIManager != null)
{
Vector2 enemyScale = enemyManager.enemyUIManager.GetEnemyImageScale();
ES3.Save("EnemyImageScaleX", enemyScale.x, saveFileName);
ES3.Save("EnemyImageScaleY", enemyScale.y, saveFileName);
}
Debug.Log($"敵の情報をセーブ: {enemyManager.enemy.name} Lv.{enemyManager.enemy.level} HP:{enemyManager.enemy.currentHP}/{enemyManager.enemy.maxHP}");
}
}
catch (System.Exception e)
{
Debug.LogError($"敵の情報セーブエラー: {e.Message}");
}
}
// 敵の情報をロード
private void LoadEnemyData()
{
try
{
if (ES3.KeyExists("EnemyName", saveFileName))
{
// 敵のデータをロード
string enemyName = ES3.Load<string>("EnemyName", saveFileName);
int enemyLevel = ES3.Load<int>("EnemyLevel", saveFileName);
int enemyCurrentHP = ES3.Load<int>("EnemyCurrentHP", saveFileName);
int enemyMaxHP = ES3.Load<int>("EnemyMaxHP", saveFileName);
int enemyAttack = ES3.Load<int>("EnemyAttack", saveFileName);
int enemyDefense = ES3.Load<int>("EnemyDefense", saveFileName);
int enemyExpReward = ES3.Load<int>("EnemyExpReward", saveFileName);
int enemyGoldReward = ES3.Load<int>("EnemyGoldReward", saveFileName);
float enemyCriticalRate = ES3.Load<float>("EnemyCriticalRate", saveFileName);
float enemyCriticalDamageMultiplier = ES3.Load<float>("EnemyCriticalDamageMultiplier", saveFileName);
// 敵のサイズ情報をロード
Vector2 enemyScale = Vector2.one; // デフォルトサイズ
if (ES3.KeyExists("EnemyImageScaleX", saveFileName) && ES3.KeyExists("EnemyImageScaleY", saveFileName))
{
enemyScale.x = ES3.Load<float>("EnemyImageScaleX", saveFileName);
enemyScale.y = ES3.Load<float>("EnemyImageScaleY", saveFileName);
}
// EnemyManagerに敵のデータを復元
enemyManager.RestoreEnemyFromSaveData(enemyName, enemyLevel, enemyCurrentHP, enemyMaxHP,
enemyAttack, enemyDefense, enemyExpReward, enemyGoldReward,
enemyCriticalRate, enemyCriticalDamageMultiplier);
// 敵のサイズ情報を設定
if (enemyManager.enemyUIManager != null)
{
enemyManager.enemyUIManager.SetEnemyImageScale(enemyScale);
}
Debug.Log($"敵の情報をロード: {enemyName} Lv.{enemyLevel} HP:{enemyCurrentHP}/{enemyMaxHP} サイズ:{enemyScale}");
}
}
catch (System.Exception e)
{
Debug.LogError($"敵の情報ロードエラー: {e.Message}");
}
}
Unityでの設定
- SaveManagerに、PlayerManagerやSkillManagerなどの各マネージャーをInspectorで紐付けます。
- 保存や読込のタイミングでSaveManagerの各メソッドが実行されるようにします。

動作確認
ゲームをプレイして、
- ステージを進める
- 強化やアーティファクトを入手
- BGM音量を変更
…などの操作を行ってからアプリを再起動してみたところ、しっかりすべて復元されていました!

まとめ
今回は、ゲーム全体を通して重要な情報をセーブできるようにする処理を実装しました!
これで、プレイヤーの進行がしっかり保存される、“ゲームらしい”完成度に一歩近づきました!
次回予告
次回は「転生機能」を実装します!
繰り返し遊べるゲームにしていきましょう。
お楽しみに!

