Unity 之 模拟王者荣耀七日签到系统

简介: 做一个模拟王者荣耀的签到系统,七日签到不可补签,下周自动重置。

一,效果图

不带补签版本:
1.2


二,制作思路

使用切换图片背景颜色的方式,进行状态转换【灰色:已签到;蓝色:可签到;白色:未签到】

主要逻辑:

  • 每次签到时保存一个签到日期,用于判断今日是否签到;
  • 根据是否已签到显示UI界面,提示信息等;
  • 未签到时,点击按钮,进行签到(保存签到日期,发放奖励,维护UI显示等);
  • 另外,还需要进行新的一周签到开始的逻辑重置;

上述逻辑,基本上模拟了王者荣耀的签到面板功能了,下面我们开始实现吧。


三,场景搭建

3.1
Demo场景搭建如上图:(没有资源有点丑~)

  1. 制作一个签到按钮(一个Image,下面放了一个Image和一个Text)
  2. 复制六份(单独创建一个空物体,作为它们的父物体)
  3. 创建一个文本(随便放在哪里,显示提示信息用的)

四,代码实现

就是按上面说的实现的逻辑,代码中注释也写的很详细了,全部代码如下:

using System;
using UnityEngine;
using UnityEngine.UI;

public class SingInDemo : MonoBehaviour
{
    // 签到按钮的父物体
    public Transform WeekParent;
    
    // 提示文字
    public Text HintText;
    
    // 上次签到时间 -- 和今天时间对比,确定是否今日已签到
    private readonly string prefsLastCheckTime = "prefsLastCheckTime";
    
    // 本周已签到几天 例:2 --> 表示周一,周二已签到
    private readonly string prefsWeekAlreadyDay = "prefsWeekAlreadyDay";

    // 今天周几
    private int weekToday;
    // 本周签到了几天
    private int alreadyDay;

    void Start()
    {
        //PlayerPrefs.DeleteAll();
        weekToday = GetDateWeek(DateTime.Now.ToString());

        AlreadyByWeek();
        // 查看本周签到了几天了
        alreadyDay = PlayerPrefs.GetInt(prefsWeekAlreadyDay);

        for (int i = 0; i < WeekParent.childCount; i++)
        {
            GameObject go = WeekParent.GetChild(i).gameObject;
            // 监听按钮点击
            go.GetComponent<Button>().onClick.AddListener(() => { OnClickSingInBtn(go); });

            // 标识是否已签到
            bool isAlready = alreadyDay > i;
            go.GetComponent<Image>().color = isAlready ? Color.gray : Color.white;
            go.transform.GetChild(1).gameObject.SetActive(isAlready);
        }

        // 今天还没签到
        if (!AlreadyByToDay())
        {
            WeekParent.GetChild(alreadyDay).GetComponent<Image>().color = Color.cyan;
        }

        // 显示提示信息
        ShowHintText(alreadyDay);
    }

    // 点击签到按钮
    private void OnClickSingInBtn(GameObject go)
    {
        // 点了星期 ?签到按钮
        string week = go.name.Split('_')[1];
        Debug.Log("点击了..." + go.name + "按钮, 是周" + week);

        // 可签到
        alreadyDay = PlayerPrefs.GetInt(prefsWeekAlreadyDay);
        if (!AlreadyByToDay()) 
        {
            Debug.Log("签到成功,签到成功的是,是周" + week);
            go.transform.GetChild(1).gameObject.SetActive(true);
            go.transform.GetComponent<Image>().color = Color.gray;
            PlayerPrefs.SetString(prefsLastCheckTime, DateTime.Now.ToString("d"));
            PlayerPrefs.SetInt(prefsWeekAlreadyDay, ++alreadyDay);

            // 显示提示信息
            ShowHintText(alreadyDay);
            Debug.Log("~~~~~~~~~~~~ 签到成功的奖励还没写哦 ~~~~~~~~~~~~");
        }
        else
        {
            Debug.Log("今日已签到,不能重复签到哦~");
        }
    }

    /// <summary>
    /// 本周是是否已签到 -- 计算上次签到时间 是不是在本周内
    /// </summary>
    void AlreadyByWeek()
    {
        if (!PlayerPrefs.HasKey(prefsLastCheckTime)) return;
        
        // 本周周一
        string startWeek = GetMondayDate(DateTime.Now).ToString("d");
        // 上次签到时间的周一
        DateTime dtmE = DateTime.Parse(PlayerPrefs.GetString(PlayerKey.SigninLastCheckTime.ToString()));
        string lastWeek =  GetMondayDate(dtmE).ToString("d");

        // 上次签到周不是本周 && 今日未签到 
        if (startWeek != lastWeek && !AlreadyByToDay())
        {
            Debug.Log("新的一周开始,重置所有签到信息...");
            PlayerPrefs.DeleteKey(prefsLastCheckTime);
            PlayerPrefs.DeleteKey(prefsWeekAlreadyDay);
        }
    }

    /// <summary>
    /// 今天是否已签到
    /// </summary>
    /// <returns></returns>
    bool AlreadyByToDay()
    {
        string today = DateTime.Now.ToString("d");
        return PlayerPrefs.GetString(prefsLastCheckTime) == today;
    }
    
    /// <summary>
    /// 返回传入日期是周几
    /// </summary>
    /// <param name="strYMD"></param>
    /// <returns></returns>
    int GetDateWeek(string strYMD)
    {
        int week = Convert.ToInt32(Convert.ToDateTime(strYMD).DayOfWeek);
        // 0:表示是周日
        return week != 0 ? week : 7;
    }

    // 提示文本
    void ShowHintText(int alreadyDay)
    {
        if (!AlreadyByToDay())
        {
            HintText.text = "今日未签到, 本周已签到" + alreadyDay + " 天";
        }
        else
        {
            HintText.text = "今日已签到,本周已签: " + alreadyDay + " 天, 可补签" +  (weekToday - alreadyDay) + " 天";;
        }
    }
    /// <summary>
    /// 计算某日起始日期(礼拜一的日期)
    /// </summary>
    /// <param name="someDate">该周中任意一天</param>
    /// <returns>返回礼拜一日期,后面的具体时、分、秒和传入值相等</returns>
    DateTime GetMondayDate(DateTime someDate)
    {
        int i = someDate.DayOfWeek - DayOfWeek.Monday;
        if (i == -1) i = 6;// i值 > = 0 ,因为枚举原因,Sunday排在最前,此时Sunday-Monday=-1,必须+7=6。
        TimeSpan ts = new TimeSpan(i, 0, 0, 0);
        return someDate.Subtract(ts);
    }
}

五,拓展补签版本

顺着上面的实现思路,很容易就是可以实现一个带补签的版本:

看下效果图:
1.2
其实就是把上面代码校验今天是否已签到的地方修改为是否可补签,然后添加一个补签逻辑就可以了。

场景搭建还是和上面一样,代码实现如下:

using System;
using UnityEngine;
using UnityEngine.UI;

public class SingInDemo : MonoBehaviour
{
    // 签到按钮的父物体
    public Transform WeekParent;
    
    // 提示文字
    public Text HintText;
    
    // 上次签到时间 -- 和今天时间对比,确定是否今日已签到
    private readonly string prefsLastCheckTime = "prefsLastCheckTime";
    
    // 本周已签到几天 例:2 --> 表示周一,周二已签到
    private readonly string prefsWeekAlreadyDay = "prefsWeekAlreadyDay";

    // 今天周几
    private int weekToday;
    // 本周签到了几天
    private int alreadyDay;

    void Start()
    {
        //PlayerPrefs.DeleteAll();
        weekToday = GetDateWeek(DateTime.Now.ToString());

        AlreadyByWeek();
        // 查看本周签到了几天了
        alreadyDay = PlayerPrefs.GetInt(prefsWeekAlreadyDay);

        for (int i = 0; i < WeekParent.childCount; i++)
        {
            GameObject go = WeekParent.GetChild(i).gameObject;
            // 监听按钮点击
            go.GetComponent<Button>().onClick.AddListener(() => { OnClickSingInBtn(go); });

            // 标识是否已签到
            bool isAlready = alreadyDay > i;
            go.GetComponent<Image>().color = isAlready ? Color.gray : Color.white;
            go.transform.GetChild(1).gameObject.SetActive(isAlready);
        }

        // 今天还没签到
        if (weekToday - alreadyDay > 0)  //(!AlreadyByToDay()) // todo...不可补签使用 
        {
            WeekParent.GetChild(alreadyDay).GetComponent<Image>().color = Color.cyan;
        }

        // 显示提示信息
        ShowHintText(alreadyDay);
    }

    // 点击签到按钮
    private void OnClickSingInBtn(GameObject go)
    {
        // 点了星期 ?签到按钮
        string week = go.name.Split('_')[1];
        Debug.Log("点击了..." + go.name + "按钮, 是周" + week);

        // 可签到
        alreadyDay = PlayerPrefs.GetInt(prefsWeekAlreadyDay);
        if (weekToday - alreadyDay > 0)  //(!AlreadyByToDay()) // todo...不可补签使用 
        {
            Debug.Log("签到成功,签到成功的是,是周" + week);
            go.transform.GetChild(1).gameObject.SetActive(true);
            go.transform.GetComponent<Image>().color = Color.gray;
            PlayerPrefs.SetString(prefsLastCheckTime, DateTime.Now.ToString("d"));
            PlayerPrefs.SetInt(prefsWeekAlreadyDay, ++alreadyDay);

            // 显示提示信息
            ShowHintText(alreadyDay);

            #region 补签逻辑 -- todo..不需补签直接删掉即可
            if (AlreadyByToDay())
            {
                Debug.Log("--- 补签成功, 这是本周第" + alreadyDay + "次签到 ---");
            }
            else
            {
                Debug.Log("+++ 签到成功, 这是本周第" + alreadyDay + "次签到 +++");
            }

            // 可补签~,添加可点击标识
            if (weekToday - alreadyDay > 0)
            {
                WeekParent.GetChild(alreadyDay).GetComponent<Image>().color = Color.cyan;
            }
            #endregion
            
            Debug.Log("~~~~~~~~~~~~ 签到成功的奖励还没写哦 ~~~~~~~~~~~~");
        }
        else
        {
            Debug.Log("今日已签到,不能重复签到哦~");
        }
    }

    /// <summary>
    /// 本周是是否已签到 -- 计算上次签到时间 是不是在本周内
    /// </summary>
    void AlreadyByWeek()
    {
        if (!PlayerPrefs.HasKey(prefsLastCheckTime)) return;
        
       // 本周周一
        string startWeek = GetMondayDate(DateTime.Now).ToString("d");
        // 上次签到时间的周一
        DateTime dtmE = DateTime.Parse(PlayerPrefs.GetString(PlayerKey.SigninLastCheckTime.ToString()));
        string lastWeek =  GetMondayDate(dtmE).ToString("d");

        // 上次签到周不是本周 && 今日未签到 
        if (startWeek != lastWeek && !AlreadyByToDay())
        {
            Debug.Log("新的一周开始,重置所有签到信息...");
            PlayerPrefs.DeleteKey(prefsLastCheckTime);
            PlayerPrefs.DeleteKey(prefsWeekAlreadyDay);
        }
    }

    /// <summary>
    /// 今天是否已签到
    /// </summary>
    /// <returns></returns>
    bool AlreadyByToDay()
    {
        string today = DateTime.Now.ToString("d");
        return PlayerPrefs.GetString(prefsLastCheckTime) == today;
    }
    
    /// <summary>
    /// 返回传入日期是周几
    /// </summary>
    /// <param name="strYMD"></param>
    /// <returns></returns>
    int GetDateWeek(string strYMD)
    {
        int week = Convert.ToInt32(Convert.ToDateTime(strYMD).DayOfWeek);
        // 0:表示是周日
        return week != 0 ? week : 7;
    }

    // 提示文本
    void ShowHintText(int alreadyDay)
    {
        if (!AlreadyByToDay())
        {
            HintText.text = "今日未签到, 本周已签到" + alreadyDay + " 天";
        }
        else
        {
            HintText.text = "今日已签到,本周已签: " + alreadyDay + " 天, 可补签" +  (weekToday - alreadyDay) + " 天";;
        }
    }

    /// <summary>
    /// 计算某日起始日期(礼拜一的日期)
    /// </summary>
    /// <param name="someDate">该周中任意一天</param>
    /// <returns>返回礼拜一日期,后面的具体时、分、秒和传入值相等</returns>
    DateTime GetMondayDate(DateTime someDate)
    {
        int i = someDate.DayOfWeek - DayOfWeek.Monday;
        if (i == -1) i = 6;// i值 > = 0 ,因为枚举原因,Sunday排在最前,此时Sunday-Monday=-1,必须+7=6。
        TimeSpan ts = new TimeSpan(i, 0, 0, 0);
        return someDate.Subtract(ts);
    }
}
相关文章
|
3月前
|
图形学 开发者 UED
Unity游戏开发必备技巧:深度解析事件系统运用之道,从生命周期回调到自定义事件,打造高效逻辑与流畅交互的全方位指南
【8月更文挑战第31天】在游戏开发中,事件系统是连接游戏逻辑与用户交互的关键。Unity提供了多种机制处理事件,如MonoBehaviour生命周期回调、事件系统组件及自定义事件。本文介绍如何有效利用这些机制,包括创建自定义事件和使用Unity内置事件系统提升游戏体验。通过合理安排代码执行时机,如在Awake、Start等方法中初始化组件,以及使用委托和事件处理复杂逻辑,可以使游戏更加高效且逻辑清晰。掌握这些技巧有助于开发者更好地应对游戏开发挑战。
160 0
|
4月前
|
图形学 C# 开发者
Unity粒子系统全解析:从基础设置到高级编程技巧,教你轻松玩转绚丽多彩的视觉特效,打造震撼游戏画面的终极指南
【8月更文挑战第31天】粒子系统是Unity引擎的强大功能,可创建动态视觉效果,如火焰、爆炸等。本文介绍如何在Unity中使用粒子系统,并提供示例代码。首先创建粒子系统,然后调整Emission、Shape、Color over Lifetime等模块参数,实现所需效果。此外,还可通过C#脚本实现更复杂的粒子效果,增强游戏视觉冲击力和沉浸感。
277 0
|
4月前
|
开发者 图形学 前端开发
绝招放送:彻底解锁Unity UI系统奥秘,五大步骤教你如何缔造令人惊叹的沉浸式游戏体验,从Canvas到动画,一步一个脚印走向大师级UI设计
【8月更文挑战第31天】随着游戏开发技术的进步,UI成为提升游戏体验的关键。本文探讨如何利用Unity的UI系统创建美观且功能丰富的界面,包括Canvas、UI元素及Event System的使用,并通过具体示例代码展示按钮点击事件及淡入淡出动画的实现过程,助力开发者打造沉浸式的游戏体验。
116 0
|
4月前
|
图形学
Unity动画☀️Unity动画系统Bug集合
Unity动画☀️Unity动画系统Bug集合
|
6月前
|
存储 JSON 关系型数据库
【unity实战】制作unity数据保存和加载系统——大型游戏存储的最优解
【unity实战】制作unity数据保存和加载系统——大型游戏存储的最优解
191 2
|
6月前
|
图形学 索引
【制作100个unity游戏之25】3D背包、库存、制作、快捷栏、存储系统、砍伐树木获取资源、随机战利品宝箱4(附带项目源码)
【制作100个unity游戏之25】3D背包、库存、制作、快捷栏、存储系统、砍伐树木获取资源、随机战利品宝箱4(附带项目源码)
121 2
|
6月前
|
Rust 图形学
【unity实战】使用unity制作一个类似Rust的3D生存建造建筑系统,具有很好的吸附性(附项目源码)
【unity实战】使用unity制作一个类似Rust的3D生存建造建筑系统,具有很好的吸附性(附项目源码)
161 1
|
6月前
|
图形学
【制作100个unity游戏之25】3D背包、库存、制作、快捷栏、存储系统、砍伐树木获取资源、随机战利品宝箱10(附带项目源码)
【制作100个unity游戏之25】3D背包、库存、制作、快捷栏、存储系统、砍伐树木获取资源、随机战利品宝箱10(附带项目源码)
60 1
|
6月前
|
图形学
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统(下)
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统
93 0
|
6月前
|
图形学 容器
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统(上)
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统
100 0