You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中应用退出到重启时长计算异常问题排查

问题根源

你遇到的异常时长是因为退出时间没有被持久化存储。TimeQuitRecorder里的_timeQuit是静态变量,当Unity应用完全退出后,所有内存中的数据(包括静态变量)都会被销毁。重启应用后,_timeQuit会被初始化为System.DateTime.MinValue(即公元1年1月1日),用当前时间减去这个值,自然会得到一个极大的时间差,也就是你看到的63826919893.997秒。

修复方案

需要将退出时间保存到持久化存储中,比如Unity的PlayerPrefs,或者你已有的PlayerData系统。下面是基于PlayerPrefs的修改方案:

修改TimeQuitRecorder类

using UnityEngine;

public class TimeQuitRecorder : MonoBehaviour
{
    public static TimeQuitRecorder instance;
    private const string TimeQuitKey = "LastQuitTime";
    public System.DateTime TimeQuit { get; private set; }

    private void Awake()
    {
        if (instance == null)
        {
            instance = this;
            DontDestroyOnLoad(gameObject);
            // 启动时从PlayerPrefs加载上次退出时间
            LoadLastQuitTime();
        }
        else
        {
            Destroy(gameObject);
        }
    }

    private void OnApplicationQuit()
    {
        // 退出时保存当前时间到PlayerPrefs
        SaveCurrentTime();
    }

    private void SaveCurrentTime()
    {
        // 将DateTime转换为可存储的字符串(ISO格式)
        string timeString = System.DateTime.Now.ToString(System.DateTimeFormatInfo.InvariantInfo.SortableDateTimePattern);
        PlayerPrefs.SetString(TimeQuitKey, timeString);
        PlayerPrefs.Save();
    }

    private void LoadLastQuitTime()
    {
        if (PlayerPrefs.HasKey(TimeQuitKey))
        {
            string timeString = PlayerPrefs.GetString(TimeQuitKey);
            // 解析字符串为DateTime
            if (System.DateTime.TryParse(timeString, System.DateTimeFormatInfo.InvariantInfo, System.DateTimeStyles.None, out System.DateTime loadedTime))
            {
                TimeQuit = loadedTime;
            }
            else
            {
                // 解析失败时设为当前时间(避免异常差值)
                TimeQuit = System.DateTime.Now;
            }
        }
        else
        {
            // 第一次启动时,设为当前时间
            TimeQuit = System.DateTime.Now;
        }
    }
}

优化CoinGenerator类的异常处理

给CoinsEarnedSincePlayerQuit方法添加系统时间回拨的判断,避免出现负数时长:

private float CoinsEarnedSincePlayerQuit ()
{
    System.DateTime now = System.DateTime.Now;
    System.TimeSpan secondsSinceQuit = now.Subtract(TimeQuitRecorder.instance.TimeQuit); 

    // 处理系统时间被回拨的情况,避免负数时长
    if (secondsSinceQuit.TotalSeconds < 0)
    {
        Debug.LogWarning("系统时间被回拨,重置离线时长为0");
        secondsSinceQuit = System.TimeSpan.Zero;
    }

    float generatedCoins = coinsPerHour * ((float)secondsSinceQuit.TotalSeconds / 3600f);
    float coinsEarned = Mathf.Clamp(generatedCoins, 0, capacity);

    Debug.Log("离线时长(秒): " + secondsSinceQuit.TotalSeconds);
    return coinsEarned;
}
额外注意事项
  • 如果你使用PlayerData进行持久化,可以将退出时间存储到你的PlayerData对象中,再保存到本地文件或云端,比PlayerPrefs更适合复杂数据场景。
  • 跨平台测试:不同平台的PlayerPrefs存储位置不同,但Unity已做兼容处理,无需额外调整。
  • 防作弊:如果需要防止用户修改系统时间刷金币,可以考虑接入服务器时间校验——记录上次在线时的服务器时间,下次启动时和服务器同步计算离线时长。

内容的提问来源于stack exchange,提问作者Clarc Jae Virgil Magbujos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 05:40:31