【Unity】ゲームを閉じていた時間の計算|すぐ使える実例集#2

当ブログではアフィリエイト広告を含みます
Unity

今日からすぐに使えるUnity実例集の第2弾です。
これは「他のアプリでよく見るアレ」を実装していこうじゃないかという企画ですので、そのうちあなたが求めている実装を紹介するかもしれません。是非チェックしにきてください。


スマホゲーム界隈では放置系RPGが流行っていますが、この手のゲームではアプリを開くとドッサリと報酬がもらえたりします。ゲームを起動していないのに「8時間分の報酬です」などと表示されたりしますが、これはどういう仕組なのでしょうか。

今回のポイント、放置報酬は「ゲームを閉じていた時間を正しく計算できているか」でほぼ決まります。

というわけで今回は、前回の発展形として
ゲームを閉じていた時間を正確に計算する仕組み
Unityでコピペ実装していきます。

放置時間計算の基本方針

やることはシンプルです。

  1. ゲームを閉じる(またはバックグラウンドに入る)直前に
    「その時刻」を保存
  2. 次回起動時に「現在時刻」と比較
  3. 差分=放置していた時間

これだけで、放置系ゲームの報酬ロジックにそのまま使えます。

実装のポイント

重要なのは2点です。

端末の現在時刻を保存すること
秒単位で差分を取ること

今回は扱いやすさ重視で、
DateTimePlayerPrefs を使います。

コピペで動く実装例

放置時間を管理するクラス

using UnityEngine;
using System;

public class OfflineTimeManager : MonoBehaviour
{
    private const string LAST_PLAY_TIME_KEY = "LastPlayTime";

    void Start()
    {
        CalculateOfflineTime();
    }

    void OnApplicationPause(bool pause)
    {
        if (pause)
        {
            SaveCurrentTime();
        }
    }

    void OnApplicationQuit()
    {
        SaveCurrentTime();
    }

    void SaveCurrentTime()
    {
        string now = DateTime.UtcNow.ToString("o");
        PlayerPrefs.SetString(LAST_PLAY_TIME_KEY, now);
        PlayerPrefs.Save();
    }

    void CalculateOfflineTime()
    {
        if (!PlayerPrefs.HasKey(LAST_PLAY_TIME_KEY))
        {
            // 初回起動時
            SaveCurrentTime();
            return;
        }

        string lastTimeStr = PlayerPrefs.GetString(LAST_PLAY_TIME_KEY);
        DateTime lastTime = DateTime.Parse(lastTimeStr, null, System.Globalization.DateTimeStyles.RoundtripKind);
        DateTime now = DateTime.UtcNow;

        TimeSpan offlineSpan = now - lastTime;
        double offlineSeconds = offlineSpan.TotalSeconds;

        Debug.Log($"オフライン時間:{offlineSeconds} 秒");

        // ここで報酬計算に使う
        ApplyOfflineReward(offlineSeconds);
    }

    void ApplyOfflineReward(double offlineSeconds)
    {
        // 例:1秒につき1コイン
        int reward = Mathf.FloorToInt((float)offlineSeconds);
        Debug.Log($"獲得コイン:{reward}");

        // PlayerDataなどに加算する処理だったりダイアログを開いたり以下略
    }
}

OfflineTimeManager.cs として保存。
このスクリプトを常に存在するオブジェクト(GameManagerなど)にアタッチすればOKです。

なぜ UTC 時刻を使うのか?

端末のローカル時刻を使うと、「時刻変更」「タイムゾーン変更」「サマータイム」などで、放置時間がズレる可能性があります。

DateTime.UtcNow を使っておけば、少なくとも「端末内では一貫した時刻」で扱えます。

※完全な不正対策をしたい場合は、サーバー時刻併用が必要ですが、今回は割愛します

放置報酬ロジックに組み込むときの注意

実運用では、上限時間を設けるのがほぼ必須です。

例えば、「最大24時間まで」「それ以上は打ち止め」などにしておかないと
1年ぶり起動でカンスト報酬!このゲームは1年放置が最適解!!
みたいなよくわからないことが起きます。

double maxSeconds = 24 * 60 * 60;
offlineSeconds = Math.Min(offlineSeconds, maxSeconds);

24時間で打ち止めにするなら、ApplyOfflineReward() 内にこのようなコードを追加するだけで、安全性がかなり上がります。

まとめ

放置時間の計算は、

・終了(中断)時刻を保存
・起動時に差分を取る

この2ステップだけで実装できます。

放置系ゲームでは、この仕組みがゲーム体験の土台になります。

前回/次回の記事リンク

Unity/C# をもっと体系的に学ぶには?
【現役メンターに質問しながら短期集中】
👉️ Unityコースで学んでみる [PR]
タイトルとURLをコピーしました