在单机游戏中,前端通常要做时间循环相关控制。如:某个活动固定周二开启、固定每月某个时间开启、登录后每隔4天开启(首购礼包)、注册后按照注册日期每隔5天开启等,这通常需要一个时间循环管理器。
配置表导出格式:
public partial class TimeCycleConfig{
/// <summary>
/// 循环ID
/// </summary>
public int Id;
/// <summary>
/// 当前循环时间描述
/// </summary>
public string Disc;
/// <summary>
/// 日期规则
/// 1:按照注册天数计算
/// 2:按照登录天数计算
/// 3:按照每周计算
/// 4:按照每月计算
/// </summary>
public int DateRule;
/// <summary>
/// 循环周期(天)
/// 周、月计算时默认0
/// </summary>
public int CyclePeriod;
/// <summary>
/// 在循环内第几个小时开始(单位:H)
/// </summary>
public int StartTime;
/// <summary>
/// 持续时间(单位:H)
/// </summary>
public int Duration;
public static TimeCycleConfig[] GetDatas(){
return Datas;
}
// TimeCycleConfig 共计 [1] 条数据
public static TimeCycleConfig[] Datas = new TimeCycleConfig[]{
new TimeCycleConfig{
Id=1, Disc="破冰礼包(首购礼包)", DateRule=1, CyclePeriod=3, StartTime=0, Duration=48, },
};
}
循环管理器:
using Newtonsoft.Json;
using SG.Utils;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TimeCycleManager : MonoSingleton<TimeCycleManager>
{
#region 内部循环数据类定义
public enum TimeCycleEvent
{
//循环更新,1秒更新一次
Update,
}
public enum TimeCycleStatus
{
NotOpen, //未开启
Running, //进行中
Finished //当前周期已结束
}
[Serializable]
public class CycleData
{
public TimeCycleStatus mStatus;
public TimeCycleConfig mConf;
//剩余时间,单位秒
public int mLeftTime = 0;
//获取本周期当前时间减去开始时间差值,单位秒
int GetLeftTime()
{
var now = DateTime.Now;
int escapeDays = GetEscapeDays(now);
int escapeHours = now.Hour + escapeDays * 24;
if (escapeHours < mConf.StartTime) //没有开始
{
mStatus = TimeCycleStatus.NotOpen;
return 0;
}
else if (escapeHours >= mConf.StartTime + mConf.Duration) //已经结束
{
mStatus = TimeCycleStatus.Finished;
return 0;
}
else
{
mStatus = TimeCycleStatus.Running;
return (mConf.StartTime + mConf.Duration - escapeHours - 1) * 60 * 60 + (60 - now.Minute - 1) * 60 + (60 - now.Second);
}
}
int GetEscapeDays(DateTime date)
{
if (mConf.DateRule == 1)
{
return (int)(TimeManager.Instance.SortLoginDay - 1) % mConf.CyclePeriod;
}
else if (mConf.DateRule == 2)
{
return (int)(TimeManager.Instance.AllLoginDay - 1) % mConf.CyclePeriod;
}
else if (mConf.DateRule == 3) //以周开始的话,周一为第一天
{
if (date.DayOfWeek == DayOfWeek.Sunday)
{
return 6;
}
else
{
return (int)date.DayOfWeek - 1;
}
}
else if (mConf.DateRule == 4)
{
return date.Month - 1;
}
return 10000000;
}
//TimeCycleManager调用,每秒更新一次
public void OnUpdatePerSec()
{
this.mLeftTime = GetLeftTime();
GameEventMgr.Instance.SendEvent(TimeCycleEvent.Update, this);
}
}
#endregion
[SerializeField]
List<CycleData> mCycleDataList = new List<CycleData>();
public new void Init()
{
base.Init();
foreach (var item in TimeCycleConfig.Datas)
{
mCycleDataList.Add(new CycleData
{
mConf = item
});
}
StartCoroutine(UpdatePerSec());
}
public CycleData GetCycleData(int cycleId)
{
foreach (var item in mCycleDataList)
{
if (item.mConf.Id == cycleId)
{
return item;
}
}
return null;
}
IEnumerator UpdatePerSec()
{
var wait = new WaitForSeconds(1);
while (true)
{
try
{
//延迟原因:避免TimeManager登录日期尚未更新(其他文章中)
DelayTimeManager.Instance.delay_time_run(0.2f, delegate
{
foreach (var cycleData in mCycleDataList)
{
cycleData.OnUpdatePerSec();
}
});
}
catch (Exception e)
{
DebugUtils.LogError(e.Message + "/n" + e.StackTrace);
}
yield return wait;
}
}
}