Unity开发--单机游戏中的时间管理(附带: Editor模式停止运行游戏调用OnApplicationQuit)

在单机游戏开发中(某些网络游戏也需要),经常需要统计玩家的登录数据,比如:登录次数、注册天数、注册日期、上次登录|退出时间、是否是新的一天登录等。
以下为通用的时间管理器:

using Newtonsoft.Json;
using SG.Utils;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

#if UNITY_EDITOR
using UnityEditor;
#endif


public class TimeManager2 : MonoSingleton<TimeManager2>
{
    [Serializable]
    public class TimeLocal
    {
        public TimeLocal()
        {
            var now = DateTime.Now;
            mFirstLoginTicks = now.Ticks;
            mLastLoginTicks = now.Ticks;
            mLastQuitGameTicks = now.Ticks;
            mDaysOfLogin = 1;
            mDaysOfRegistration = 1;
        }
       
        //首次登录时间
        public long mFirstLoginTicks = 0;
        //上次打开游戏时间
        public long mLastLoginTicks = 0;
        //上次退出游戏时间
        public long mLastQuitGameTicks = 0;
        //登录天数
        public int mDaysOfLogin = 0;
        //注册天数
        public int mDaysOfRegistration = 0;

        //进入游戏回调
        public void OnInGame()
        {
            var now = DateTime.Now;
            var registerDate = new DateTime(mFirstLoginTicks);
            if (!IsSameDay(now, registerDate))
            {
                var span = now - registerDate;
                if (span.TotalSeconds > 0 && span.TotalSeconds < 24 * 60 * 60)
                {
                    mDaysOfRegistration = 2;
                }
                else
                {
                    mDaysOfRegistration = span.Days + 1;
                }
            }

            var lastLoginTime = new DateTime(mLastLoginTicks);
            if (!IsSameDay(now, lastLoginTime))
            {
                TimeManager2.Instance.mIsNewDay = true;
                mDaysOfLogin++;
            }
            else
            {
                TimeManager2.Instance.mIsNewDay = false;
            }
        }

        //退出游戏回调
        public void OnQuitGame()
        {
            mLastLoginTicks = TimeManager2.Instance.mLoginTicks;
            mLastQuitGameTicks = DateTime.Now.Ticks;
        }

        //游戏中跨天回调
        public void OnAcrossDay()
        {
            OnInGame();
            //跨天后重置登录时间
            TimeManager2.Instance.mLoginTicks = DateTime.Now.Ticks;
            mLastLoginTicks = TimeManager2.Instance.mLoginTicks;
            mLastQuitGameTicks = TimeManager2.Instance.mLoginTicks;
        }

        public bool IsSameDay(DateTime d1, DateTime d2)
        {
            if (d1.Year == d2.Year && d1.Month == d2.Month && d1.Day == d2.Day)
            {
                return true;
            }
            return false;
        }
    }
    string mLocalKeyOfTimeLocal = "mLocalKeyOfTimeLocal===";

    //持久化时间数据
    [SerializeField]
    TimeLocal mTimeLocal = null;
    public TimeLocal UserTimeLocal { get { return mTimeLocal; } }
    [SerializeField]
    long mLoginTicks = 0;
    //今天是否是新的一天
    public bool mIsNewDay = false;
    //当前剩余时间(秒)
    public int mLeftSecondToday = 0;

    [SerializeField]
    List<Action> mAcrossDayActions = new List<Action>();
   
    [SerializeField]
    List<Action<int>> mPerSecondActions = new List<Action<int>>();

    public new void Init()
    {
        mLoginTicks = DateTime.Now.Ticks;
        string timeLocal = PlayerPrefs.GetString(mLocalKeyOfTimeLocal, "");
        if (!string.IsNullOrEmpty(timeLocal))
        {
            mTimeLocal = JsonConvert.DeserializeObject<TimeLocal>(timeLocal);
            if (mTimeLocal.mLastQuitGameTicks < mTimeLocal.mLastLoginTicks)
            {
                mTimeLocal.mLastQuitGameTicks = mTimeLocal.mLastLoginTicks;
            }
            mTimeLocal.OnInGame();
            SaveTimeLocal();
        }
        else
        {
            mTimeLocal = new TimeLocal();
            SaveTimeLocal();
        }

        StartCoroutine(UpdateBySecond());
#if UNITY_EDITOR
        UnityEditor.EditorApplication.playModeStateChanged += delegate (PlayModeStateChange state)
        {
            DebugUtils.Log("=====StateChanged:" + state);
            if (state == PlayModeStateChange.ExitingPlayMode)
            {
                OnApplicationQuit();
            }
        };
#endif
    }

    //跨天回调
    public void AddAcrossDayAction(Action action)
    {
        if (!mAcrossDayActions.Contains(action))
        {
            mAcrossDayActions.Add(action);
        }
    }

    public void RemoveAcrossDayAction(Action action)
    {
        mAcrossDayActions.Remove(action);
    }

    //每秒回调,回调参数为当天剩余秒数
    public void AddPerSecondAction(Action<int> action)
    {
        if (!mPerSecondActions.Contains(action))
        {
            mPerSecondActions.Add(action);
        }
    }

    public void RemovePerSecondAction(Action action)
    {
        mAcrossDayActions.Remove(action);
    }

    IEnumerator UpdateBySecond()
    {
        var wait1Sec = new WaitForSeconds(1);
        while (true)
        {
            var now = DateTime.Now;
             mLeftSecondToday = (23 - now.Hour) * 60 * 60 + (59 - now.Minute) * 60 + (60 - now.Second);
            DoPerSecondActions();
            yield return wait1Sec;
            var nextNow = DateTime.Now;
            if (!mTimeLocal.IsSameDay(nextNow, now))
            {
                mTimeLocal.OnAcrossDay();
                DoAcrossDayActions();
            }
        }
    }

    void DoAcrossDayActions()
    {
        foreach (var item in mAcrossDayActions)
        {
            try
            {
                item.Invoke();
            }
            catch (Exception e)
            {
                DebugUtils.LogError("TimeManager.DoAcrossDayActions: msg={0} \n stack={1}", e.Message, e.StackTrace);
            }
        }
    }

    void DoPerSecondActions()
    {
        foreach (var item in mPerSecondActions)
        {
            try
            {
                item.Invoke(mLeftSecondToday);
            }
            catch (Exception e)
            {
                DebugUtils.LogError("TimeManager.DoPerSecondActions: msg={0} \n stack={1}", e.Message, e.StackTrace);
            }
        }
    }

    private void OnApplicationQuit()
    {
        mTimeLocal.OnQuitGame();
        SaveTimeLocal();
    }

    void SaveTimeLocal()
    {
        PlayerPrefs.SetString(mLocalKeyOfTimeLocal, JsonConvert.SerializeObject(mTimeLocal));
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值