53歩目 記録機能を実装! Unityで1日1ステップ!ノンフィールドRPG開発日記

1日1歩開発日記

ふりかえり

前回はストーリー表示機能を実装しました!

ステージを進めることで物語が自然と解放されていく仕組みにより、プレイヤーに「もっと先を見たい!」という動機を与えることができました。

記録機能を実装

今回はプレイ記録を蓄積・表示する機能を実装しました!

冒険を振り返ったり、実績に近い楽しみ方を提供することで、プレイヤーのやり込み意欲を高める狙いがあります。

記録する項目は多岐にわたり、バトル・資源獲得・強化・ステージ進行・レアモンスター遭遇など、幅広いプレイ要素に対応しています。

記録する要素は

  • 総プレイ時間: ゲームをプレイした総時間
  • 転生回数: 転生を実行した総回数
  • 死亡回数: プレイヤーが死亡した総回数
  • 与えた最大ダメージ: 一度の攻撃で与えた最大ダメージ値
  • 受けた最大ダメージ: 一度の攻撃で受けた最大ダメージ値
  • 与えた総ダメージ: これまでに与えたダメージの総量
  • 受けた総ダメージ: これまでに受けたダメージの総量
  • 倒した敵の総数: これまでに倒した敵の総数
  • 連続勝利数: 連続で勝利した最大回数
  • 連続敗北数: 連続で敗北した最大回数
  • クリティカルヒット回数: クリティカルヒットを出した総回数
  • 獲得したゴールド総量: これまでに獲得したゴールドの総額
  • 獲得したダイヤ総量: これまでに獲得したダイヤの総数
  • 獲得した経験値総量: これまでに獲得した経験値の総量
  • 使用したゴールド総量: これまでに使用したゴールドの総額
  • 使用したダイヤ総量: これまでに使用したダイヤの総数
  • 獲得したアーティファクト数: これまでに獲得したアーティファクトの総数
  • 強化したアーティファクト回数: アーティファクトを強化した総回数
  • 使用した回復薬数: 回復薬を使用した総回数
  • 到達した最大ステージ: これまでに到達した最高ステージ
  • クリアしたステージ数: クリアしたステージの総数
  • レアモンスター遭遇回数: レアモンスターに遭遇した回数
  • レアモンスター討伐回数: レアモンスターを倒した回数
  • スキル使用回数: 各スキルを使用した総回数
  • G強化実行回数: G強化を実行した総回数
  • マナ強化実行回数: マナ強化を実行した総回数
  • 最大強化レベル: 各強化で到達した最大レベル
  • 最高レベル到達: これまでに到達した最高レベル
  • 最大所持ゴールド: 一度に所持した最大ゴールド数
  • 最大所持ダイヤ: 一度に所持した最大ダイヤ数

です!

スクリプトの変更

Record Manager.cs

RecordManager.csは、プレイ中に自動で記録を更新し、保存・表示する中核スクリプトです。

主な処理の流れは以下の通り:

1. データ構造の定義

RecordDataというクラスを用いて、全記録項目をひとまとめに管理しています。保存時はこのクラスごとシリアライズされます。

2. ゲーム中の自動更新

各種ゲームイベントに対応したRecord○○()というメソッドが多数用意されており、

たとえば敵を倒したときにRecordEnemyDefeated()を呼び出せば、討伐数や連勝記録が自動更新されます。

3. データ保存と読み込み

外部プラグイン「Easy Save 3(ES3)」を使用して、プレイデータを保存・復元しています。

これにより、アプリを閉じても記録が持続されます。

4. UIへの反映

Scroll View内のTextMeshProUGUIに、記録内容をフォーマットして表示しています。

時間は「00:00:00」形式で見やすく整形され、ゴールドやダメージなどの数値もカンマ区切りで読みやすくなっています。

using UnityEngine;
using UnityEngine.UI;
using TMPro;
using System;

public class RecordManager : MonoBehaviour
{
    [Header("記録表示UI")]
    public ScrollRect recordScrollRect; // 記録表示用のスクロールビュー
    public TextMeshProUGUI recordContentText; // 記録内容表示用のテキスト

    [Header("Manager References")]
    public PlayerManager playerManager;
    public SaveManager saveManager;

    // 記録データクラス
    [System.Serializable]
    public class RecordData
    {
        // 基本統計
        public float totalPlayTime = 0f; // 総プレイ時間(秒)
        public int prestigeCount = 0; // 転生回数
        public int deathCount = 0; // 死亡回数

        // 戦闘記録
        public int maxDamageDealt = 0; // 与えた最大ダメージ
        public int maxDamageReceived = 0; // 受けた最大ダメージ
        public long totalDamageDealt = 0; // 与えた総ダメージ
        public long totalDamageReceived = 0; // 受けた総ダメージ
        public int totalEnemiesDefeated = 0; // 倒した敵の総数
        public int maxConsecutiveWins = 0; // 連続勝利数
        public int maxConsecutiveLosses = 0; // 連続敗北数
        public int criticalHitCount = 0; // クリティカルヒット回数

        // 獲得記録
        public long totalGoldEarned = 0; // 獲得したゴールド総量
        public int totalDiamondEarned = 0; // 獲得したダイヤ総量
        public long totalExpEarned = 0; // 獲得した経験値総量
        public long totalGoldSpent = 0; // 使用したゴールド総量
        public int totalDiamondSpent = 0; // 使用したダイヤ総量
        public int totalArtifactsObtained = 0; // 獲得したアーティファクト数
        public int totalArtifactUpgrades = 0; // 強化したアーティファクト回数
        public int totalHealingPotionsUsed = 0; // 使用した回復薬数

        // ステージ・進行記録
        public int maxStageReached = 1; // 到達した最大ステージ
        public int totalStagesCleared = 0; // クリアしたステージ数
        public int rareMonsterEncounters = 0; // レアモンスター遭遇回数
        public int rareMonsterDefeated = 0; // レアモンスター討伐回数

        // スキル・強化記録
        public int totalSkillUses = 0; // スキル使用回数
        public int totalGPowerUps = 0; // G強化実行回数
        public int totalManaUpgrades = 0; // マナ強化実行回数
        public int maxUpgradeLevel = 0; // 最大強化レベル
        public int maxLevelReached = 1; // 最高レベル到達

        // 特殊記録
        public int maxGoldHeld = 0; // 最大所持ゴールド
        public int maxDiamondHeld = 0; // 最大所持ダイヤ
    }

    private RecordData records = new RecordData();
    private float sessionStartTime;
    private int currentConsecutiveWins = 0;
    private int currentConsecutiveLosses = 0;

    void Start()
    {
        sessionStartTime = Time.time;
        LoadRecords();
        UpdateRecordDisplay();
    }

    void Update()
    {
        // プレイ時間を更新
        records.totalPlayTime += Time.deltaTime;
    }

    // 記録を保存
    public void SaveRecords()
    {
        if (saveManager != null)
        {
            ES3.Save("RecordData", records, saveManager.saveFileName);
            Debug.Log("記録データを保存しました");
        }
    }

    // 記録を読み込み
    public void LoadRecords()
    {
        if (saveManager != null)
        {
            records = ES3.Load("RecordData", saveManager.saveFileName, new RecordData());
            Debug.Log("記録データを読み込みました");
        }
    }

    // 記録表示を更新
    public void UpdateRecordDisplay()
    {
        if (recordContentText == null) return;

        string recordText = "=== プレイヤー記録 ===\n\n";

        // 基本統計
        recordText += "【基本統計】\n";
        recordText += $"総プレイ時間: {FormatTime(records.totalPlayTime)}\n";
        recordText += $"転生回数: {records.prestigeCount}回\n";
        recordText += $"死亡回数: {records.deathCount}回\n\n";

        // 戦闘記録
        recordText += "【戦闘記録】\n";
        recordText += $"与えた最大ダメージ: {records.maxDamageDealt:N0}\n";
        recordText += $"受けた最大ダメージ: {records.maxDamageReceived:N0}\n";
        recordText += $"与えた総ダメージ: {records.totalDamageDealt:N0}\n";
        recordText += $"受けた総ダメージ: {records.totalDamageReceived:N0}\n";
        recordText += $"倒した敵の総数: {records.totalEnemiesDefeated:N0}体\n";
        recordText += $"連続勝利数: {records.maxConsecutiveWins}回\n";
        recordText += $"連続敗北数: {records.maxConsecutiveLosses}回\n";
        recordText += $"クリティカルヒット回数: {records.criticalHitCount:N0}回\n\n";

        // 獲得記録
        recordText += "【獲得記録】\n";
        recordText += $"獲得したゴールド総量: {records.totalGoldEarned:N0}G\n";
        recordText += $"獲得したダイヤ総量: {records.totalDiamondEarned:N0}個\n";
        recordText += $"獲得した経験値総量: {records.totalExpEarned:N0}EXP\n";
        recordText += $"使用したゴールド総量: {records.totalGoldSpent:N0}G\n";
        recordText += $"使用したダイヤ総量: {records.totalDiamondSpent:N0}個\n";
        recordText += $"獲得したアーティファクト数: {records.totalArtifactsObtained}個\n";
        recordText += $"強化したアーティファクト回数: {records.totalArtifactUpgrades}回\n";
        recordText += $"使用した回復薬数: {records.totalHealingPotionsUsed}個\n\n";

        // ステージ・進行記録
        recordText += "【ステージ・進行記録】\n";
        recordText += $"到達した最大ステージ: {records.maxStageReached}ステージ\n";
        recordText += $"クリアしたステージ数: {records.totalStagesCleared}ステージ\n";
        recordText += $"レアモンスター遭遇回数: {records.rareMonsterEncounters}回\n";
        recordText += $"レアモンスター討伐回数: {records.rareMonsterDefeated}回\n\n";

        // スキル・強化記録
        recordText += "【スキル・強化記録】\n";
        recordText += $"スキル使用回数: {records.totalSkillUses:N0}回\n";
        recordText += $"G強化実行回数: {records.totalGPowerUps}回\n";
        recordText += $"マナ強化実行回数: {records.totalManaUpgrades}回\n";
        recordText += $"最大強化レベル: {records.maxUpgradeLevel}レベル\n";
        recordText += $"最高レベル到達: {records.maxLevelReached}レベル\n\n";

        // 特殊記録
        recordText += "【特殊記録】\n";
        recordText += $"最大所持ゴールド: {records.maxGoldHeld:N0}G\n";
        recordText += $"最大所持ダイヤ: {records.maxDiamondHeld}個\n";

        recordContentText.text = recordText;
    }

    // 時間をフォーマット(時:分:秒)
    private string FormatTime(float seconds)
    {
        int hours = Mathf.FloorToInt(seconds / 3600);
        int minutes = Mathf.FloorToInt((seconds % 3600) / 60);
        int secs = Mathf.FloorToInt(seconds % 60);
        return $"{hours:00}:{minutes:00}:{secs:00}";
    }

    // 記録更新メソッド群
    public void RecordPrestige()
    {
        records.prestigeCount++;
        SaveRecords();
        UpdateRecordDisplay();
    }

    public void RecordDeath()
    {
        records.deathCount++;
        currentConsecutiveWins = 0;
        currentConsecutiveLosses++;
        if (currentConsecutiveLosses > records.maxConsecutiveLosses)
        {
            records.maxConsecutiveLosses = currentConsecutiveLosses;
        }
        SaveRecords();
        UpdateRecordDisplay();
    }

    public void RecordDamageDealt(int damage)
    {
        records.totalDamageDealt += damage;
        if (damage > records.maxDamageDealt)
        {
            records.maxDamageDealt = damage;
        }
        SaveRecords();
    }

    public void RecordDamageReceived(int damage)
    {
        records.totalDamageReceived += damage;
        if (damage > records.maxDamageReceived)
        {
            records.maxDamageReceived = damage;
        }
        SaveRecords();
    }

    public void RecordEnemyDefeated()
    {
        records.totalEnemiesDefeated++;
        currentConsecutiveWins++;
        currentConsecutiveLosses = 0;
        if (currentConsecutiveWins > records.maxConsecutiveWins)
        {
            records.maxConsecutiveWins = currentConsecutiveWins;
        }
        SaveRecords();
    }

    public void RecordCriticalHit()
    {
        records.criticalHitCount++;
        SaveRecords();
    }

    public void RecordGoldEarned(int amount)
    {
        records.totalGoldEarned += amount;
        SaveRecords();
    }

    public void RecordDiamondEarned(int amount)
    {
        records.totalDiamondEarned += amount;
        SaveRecords();
    }

    public void RecordExpEarned(int amount)
    {
        records.totalExpEarned += amount;
        SaveRecords();
    }

    public void RecordGoldSpent(int amount)
    {
        records.totalGoldSpent += amount;
        SaveRecords();
    }

    public void RecordDiamondSpent(int amount)
    {
        records.totalDiamondSpent += amount;
        SaveRecords();
    }

    public void RecordArtifactObtained()
    {
        records.totalArtifactsObtained++;
        SaveRecords();
    }

    public void RecordArtifactUpgrade()
    {
        records.totalArtifactUpgrades++;
        SaveRecords();
    }

    public void RecordHealingPotionUsed()
    {
        records.totalHealingPotionsUsed++;
        SaveRecords();
    }

    public void RecordStageReached(int stage)
    {
        if (stage > records.maxStageReached)
        {
            records.maxStageReached = stage;
        }
        SaveRecords();
    }

    public void RecordStageCleared()
    {
        records.totalStagesCleared++;
        SaveRecords();
    }

    public void RecordRareMonsterEncounter()
    {
        records.rareMonsterEncounters++;
        SaveRecords();
    }

    public void RecordRareMonsterDefeated()
    {
        records.rareMonsterDefeated++;
        SaveRecords();
    }

    public void RecordSkillUse()
    {
        records.totalSkillUses++;
        SaveRecords();
    }

    public void RecordGPowerUp()
    {
        records.totalGPowerUps++;
        SaveRecords();
    }

    public void RecordManaUpgrade()
    {
        records.totalManaUpgrades++;
        SaveRecords();
    }

    public void RecordUpgradeLevel(int level)
    {
        if (level > records.maxUpgradeLevel)
        {
            records.maxUpgradeLevel = level;
        }
        SaveRecords();
    }

    public void RecordLevelReached(int level)
    {
        if (level > records.maxLevelReached)
        {
            records.maxLevelReached = level;
        }
        SaveRecords();
    }

    public void RecordMaxGoldHeld(int amount)
    {
        if (amount > records.maxGoldHeld)
        {
            records.maxGoldHeld = amount;
        }
        SaveRecords();
    }

    public void RecordMaxDiamondHeld(int amount)
    {
        if (amount > records.maxDiamondHeld)
        {
            records.maxDiamondHeld = amount;
        }
        SaveRecords();
    }

    // 記録データを取得(他のスクリプトから参照用)
    public RecordData GetRecords()
    {
        return records;
    }

    // 記録データをリセット(全データ削除用)
    public void ResetRecords()
    {
        records = new RecordData();
        currentConsecutiveWins = 0;
        currentConsecutiveLosses = 0;
        sessionStartTime = Time.time;
        SaveRecords();
        UpdateRecordDisplay();
        Debug.Log("RecordManagerのデータがリセットされました。");
    }
}

Unityでの設定

空のGameObjectにRecord Manager.csをアタッチします。

RecordManagerをアタッチしたGameObjectのInsoector上で記録を表示するためのScroll ViewとText、それと各種必要なObjectをアタッチします。

UIはこのような画面になりました!

動作確認

記録は「記録」メニューから確認可能で、スクロール付きのウィンドウにカテゴリごとに整理されて表示されます。

「戦闘記録」「資源獲得」「スキル使用」「レアモンスター遭遇」など、実績画面のような達成感があります!

まとめ

今回は「記録機能」を実装しました!

  • プレイヤーの冒険の軌跡が可視化される
  • 自己ベスト更新や実績のような達成感が得られる
  • 今後の「実績機能」や「ランキング機能」にも応用可能

と、モチベーションアップに非常に効果的なシステムです。

記録の見せ方やUI演出を工夫することで、自己成長を感じやすいゲーム体験を提供できると実感しました。

進捗

今回はメニューの記録機能の追加をしました!

  • (済)オート戦闘:ボタン操作なしでもバトルが進むようにする。
  • (済)オートスキル発動:スキルも自動で発動する機能。
  • (済)UIのブラッシュアップ:デザインとレイアウトを整えて見やすくする。
  • (済)ステージ数の拡充(最低20):遊びごたえを高めるためにボリュームアップ。
  • 復活機能(広告視聴):ゲームオーバー時、広告視聴で復活できる仕組み。
  • 広告報酬でダイヤ獲得:無課金でもダイヤが手に入る仕組み。
  • (済)G強化・アーティファクト・転生の拡張:各システムにさらなる深みを持たせる。
  • (済)回復薬の追加:ステージを進めやすくする。
  • アニメーションの追加:ゲーム画面にもっと動きを持たせる。
  • (済)レアモンスターの追加:わくわく感を追加する。
  • 放置要素の追加:プレイしていない時間も強くなる。
  • (仮済)メニューの内容追加:ストーリー、記録、ガイドなどプレイヤーが遊びやすくする。

次回予告

次回は「ガイド機能」を実装予定!

初心者でも困らず進められる、親切設計を目指します!

お楽しみに!

タイトルとURLをコピーしました