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

·  阅读 344

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

一,效果图

不带补签版本: 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);
    }
}
复制代码

若还有不明白的地方,可以评论咨询,或者点击链接查看示例源码:源码链接


分类:
前端
标签:
分类:
前端
标签: