Unity游戏无法保存上次游玩日期及日期对比问题求助
Unity 每日游玩次数重置功能修复方案
问题根源分析
你的代码主要存在三个核心问题:
- 变量作用域错误:
GetCurrentTime协程内声明了局部的dateTimeStr,未赋值给类成员变量,导致类的dateTimeStr始终为null,保存到PlayerPrefs的是空值。 - 异步逻辑顺序错误:
Start方法中先启动获取日期的协程,随即执行日期对比逻辑,但协程是异步执行的,此时还未拿到服务器返回的日期,对比逻辑完全失效。 - 网络请求结果判断错误:原代码用
||判断请求结果,会把协议错误(如404)当成成功情况处理,导致错误的JSON解析。
修复后的完整代码
using System; using UnityEngine; using UnityEngine.Advertisements; using UnityEngine.Networking; using TMPro; using System.Collections; public class GameManager : MonoBehaviour, IUnityAdsLoadListener, IUnityAdsShowListener { public int maxPlayCount = 5; public int currentPlayCount; public int dailyReward = 5; public TextMeshProUGUI playCountText; public TextMeshProUGUI rewardText; private string apiEndpoint = "https://timeapi.io/api/Time/current/zone?timeZone=Europe/Istanbul"; private string dateTimeStr; private bool isAdAvailable = false; string _adUnitId = null; [SerializeField] string _androidAdUnitId = "Rewarded_Android"; [SerializeField] string _iOSAdUnitId = "Rewarded_iOS"; [Serializable] public class TimeData { public int year; public int month; public int day; public int hour; public int minute; public int seconds; public int milliSeconds; public string dateTime; public string date; public string time; public string timeZone; public string dayOfWeek; public bool dstActive; } void Awake() { #if UNITY_IOS _adUnitId = _iOSAdUnitId; #elif UNITY_ANDROID _adUnitId = _androidAdUnitId; #endif } void Start() { // 先启动日期获取协程,所有初始化逻辑移到协程完成后执行 StartCoroutine(InitializeGameWithServerDate()); } // 重构初始化逻辑,确保拿到服务器日期后再处理游玩次数 IEnumerator InitializeGameWithServerDate() { yield return GetCurrentTime(); // 确认成功拿到服务器日期后再执行后续逻辑 if (string.IsNullOrEmpty(dateTimeStr)) { Debug.LogError("无法获取服务器日期,使用本地日期作为 fallback"); dateTimeStr = DateTime.Now.ToString("yyyy-MM-dd"); } if (!PlayerPrefs.HasKey("LastPlayDateStr")) { // 首次启动,保存日期并初始化游玩次数 SavePlayDate(); Debug.Log("首次启动,初始化游玩次数"); } else { string lastPlayDateStr = PlayerPrefs.GetString("LastPlayDateStr"); Debug.Log("上次游玩日期: " + lastPlayDateStr); if (lastPlayDateStr == dateTimeStr) { // 同一天,加载已保存的游玩次数 currentPlayCount = PlayerPrefs.GetInt("CurrentPlayCount"); Debug.Log("同天游玩,加载剩余次数"); } else { // 跨天,重置游玩次数 currentPlayCount = maxPlayCount; SavePlayDate(); Debug.Log("跨天游玩,重置次数"); } } UpdateUI(); } IEnumerator GetCurrentTime() { UnityWebRequest webRequest = UnityWebRequest.Get(apiEndpoint); yield return webRequest.SendWebRequest(); // 修正请求结果判断:只有无错误时才处理 if (webRequest.result == UnityWebRequest.Result.Success) { string jsonResult = webRequest.downloadHandler.text; TimeData timeData = JsonUtility.FromJson<TimeData>(jsonResult); // 赋值给类成员变量,而非局部变量 dateTimeStr = timeData.date; Debug.Log("服务器日期: " + dateTimeStr); } else { Debug.LogError("获取服务器日期失败: " + webRequest.error); dateTimeStr = null; } } void SavePlayDate() { PlayerPrefs.SetString("LastPlayDateStr", dateTimeStr); PlayerPrefs.SetInt("CurrentPlayCount", maxPlayCount); currentPlayCount = maxPlayCount; // 保存后立即提交PlayerPrefs,避免数据丢失 PlayerPrefs.Save(); UpdateUI(); } void UpdateUI() { playCountText.text = "剩余次数: " + currentPlayCount; rewardText.text = "每日奖励: " + dailyReward; } public void PlayGame() { if (currentPlayCount > 0) { currentPlayCount--; PlayerPrefs.SetInt("CurrentPlayCount", currentPlayCount); PlayerPrefs.Save(); UpdateUI(); Debug.Log("开始游戏..."); } else { Debug.Log("次数耗尽,观看广告获取次数"); ShowAd(); } } public void OnUnityAdsAdLoaded(string _adUnitId) { Debug.Log("广告加载完成: " + _adUnitId); isAdAvailable = true; } public void OnUnityAdsFailedToLoad(string _adUnitId, UnityAdsLoadError error, string message) { Debug.LogWarning("广告加载失败: " + _adUnitId + " 错误: " + error + " 信息: " + message); isAdAvailable = false; } public void OnUnityAdsShowFailure(string _adUnitId, UnityAdsShowError error, string message) { Debug.LogWarning("广告播放失败: " + _adUnitId + " 错误: " + error + " 信息: " + message); } public void OnUnityAdsShowStart(string _adUnitId) { Debug.Log("广告开始播放: " + _adUnitId); } public void OnUnityAdsShowClick(string _adUnitId) { Debug.Log("广告被点击: " + _adUnitId); } public void OnUnityAdsShowComplete(string _adUnitId, UnityAdsShowCompletionState showCompletionState) { Debug.Log("广告播放完成: " + _adUnitId + " 状态: " + showCompletionState); if (showCompletionState == UnityAdsShowCompletionState.COMPLETED) { currentPlayCount++; PlayerPrefs.SetInt("CurrentPlayCount", currentPlayCount); PlayerPrefs.Save(); UpdateUI(); } } public void ShowAd() { if (isAdAvailable) { Advertisement.Show(_adUnitId, this); isAdAvailable = false; } else { Advertisement.Load(_adUnitId, this); } } void Update() { } }
关键修改说明
- 重构初始化流程:新增
InitializeGameWithServerDate协程,确保拿到服务器日期后再处理游玩次数逻辑,解决异步顺序问题。 - 修复变量作用域:
GetCurrentTime中直接赋值给类成员dateTimeStr,而非局部变量。 - 修正网络请求判断:使用
UnityWebRequest.Result.Success判断请求是否成功,避免错误解析。 - 增加PlayerPrefs.Save():每次修改数据后立即提交,防止数据未保存就退出。
- 广告完成逻辑优化:仅在广告完全播放完成后才增加游玩次数,避免作弊。
内容的提问来源于stack exchange,提问作者Red2Kit
相关产品推荐
相关产品推荐

