数据设计

要去设计一个独立的系统。首先第一步就是要去分析整个系统的数据结构,要去思考需要用到什么数据。

那么我们来思考一下,签到系统需要用到哪些数据呢?

我们来分析一下有哪些数据需要考虑到?

签到的次数:可以得到你签到了多少天了

签到的奖励:每日签到总会给奖励吧。所以需要一个字典去存储第一日的奖励、第2日的奖励、。。。、第n日的奖励。第n+1日奖励你如何去设计,这里我们设计的是第n+1日的奖励会回到第一日,然后依次重复。

最近一次签到的时间:最近一次签到的时间 + 24h =》就是下一次签到的时间,如果当前的时间小于下一次签到的时间就无法签到,否则就可以签到。

需求分析

接着我们来分析一下签到的逻辑:用户一打开应用APP,进入主页后,需要拿到上一次签到的日期(这里需要读取数据)。然后检查当前日期与上一次签到的日期。如果上一次签到日期不是今天,且已经过了一天,那么说明可以签到。然后接下来去看你怎么设计。

如果你想要设计连续签到:如果上一次签到的日期是昨天,那么连续天数+1。如果超过1天没有签到,那么连续天数就重置为1。(怎么设计怎么来)

或者你也可以这么设计(下面的代码就是这么设计的):只要上一次签到的日期不是今天,那么签到的天数就+1。没有考虑超过一天没有签到就重置日期。

接着我们继续分析,如果当前可以签到,就要弹出签到的UI界面,只有用户点击了签到,UI界面才会消失。

点击完签到,就要获得向对应的奖励(至于获得什么奖励,你需要自己去设计)。需要准备一个数组(其他的也行),其中每一个元素对于第n天奖励。当用户签到天数达到对应的天数时,发放对应的奖励。如果超过数组长度时,进行取模,就可以回到第一天的奖励

分析完毕后,我们将分析的内容转化为数据。

代码实现

首先是数据的设计

// 签到数据
[System.Serializable]
public class SignInData
{
    // 上一次签到的日期
    public string lastSignInDate; // ISO8601格式的日期字符串
    // 签到天数
    public int currentStreak;
}


// 奖励(这个可以直接去设计)
[System.Serializable]
public class Reward
{
    public string itemName;       // 奖励名称(如金币、钻石)
    public int amount;           // 奖励数量
}

数据设计完毕,接下来就是逻辑相关的。

现在我们先不考虑实现,可以培养一下自己的封装能力。慢慢养成架构的思维方式。

public class SignInManager : MonoBehaviour
{
    // 什么时候去判断当前是否签到(外部需要调用这个方法)
    // 签到检测
    private void 检测是否可以签到(){
        // 1. 需要读取数据,拿到上一次签到的时间,才能够判断签到
        // 2. 日期判断(只要超过一天就可以签到)
        if(判断是否可以签到){
            可以签到的方法    
        }else {
            不可以签到的方法
        }

    }

    private void 读取签到数据(){
        
    }

    private void 可以签到逻辑(){
        // 1. 显示UI面板
        // 这里UI是不是需要提供一下签到按钮,当用户按下签到按钮后,才会真正的执行签到的逻辑,并且得到奖励、然后隐藏签到UI面板
        // 如果UI界面的逻辑写在这个类的话,就违背了单一职责原则,所以我们需要另一个类,专门去处理UI界面相关的
        // 但是我们又不想要UI去处理按钮点击后的逻辑,所以我们可以向外部提供一个方法,专门去处理真正签到的逻辑,当点击这个按钮后,就调用这个外部的方法
    }

    private void 不可以签到(){
        // 什么都不需要管
    }

    public void 真正签到的逻辑(){
        // 1. 连续签到的次数+1
        // 2. 上一次签到的时间 = 当前签到的时间
        // 3. 根据当前签到的日期,获得签到的奖励
        // 4. 将数据保存到本地
        // 5. 隐藏当前的UI面板
    }

     public void 获得签到的奖励(){
        // 通过配置表去获得
        Reward reward = 配置表[签到天数];
        // 将获得的奖励添加到玩家系统中(需要与玩家系统建立联系)
        // InventoryManager.AddItem(奖励); 需要看具体是怎么设计
     }


}

由了上面代码的分析,那么实现起来将会特别简单。至于具体细节不懂的话,也不用太担心,因为有ai辅助。

// 因为外部需要调用,所以需要把SignInManager设计为单例模式
public class SignInManager : MonoSingleTonBehaviour
{
    private void LoadData()
    {
        // 从本地导入签到数据,并解析
        if (!string.IsNullOrEmpty(json))
        {
            _signInData = JsonUtility.FromJson<SignInData>(json);
        }
        else
        {
            // 如果没有数据,那么说明是第一次导入,需要初始化数据
            _signInData = new SignInData
            {
                lastSignInDate = DateTime.MinValue.ToString("O"),
                currentStreak = 0
            };
        }
    }  

    // 保存数据
    private void SaveData()
    {
        将数据转化为json保存到本地
    }

    // 是否可以签到
    public bool CanSignIn()
    {
        DateTime lastSignInDate = DateTime.Parse(_signInData.lastSignInDate);
        DateTime nextValidDate = lastSignInDate.Date.AddDays(1);
        return DateTime.Now >= nextValidDate;
    }

     // 真正的签到
     public void SignIn()
     {
        if (!CanSignIn()) return;

        DateTime now = DateTime.Now;
        DateTime lastSignInDate = DateTime.Parse(_signInData.lastSignInDate);

        // 计算连续签到
        if ((now.Date - lastSignInDate.Date).TotalDays == 1)
        {
            _signInData.currentStreak++;
        }
        else if ((now.Date - lastSignInDate.Date).TotalDays > 1)
        {
            _signInData.currentStreak = 1;
        }
        else
        {
            _signInData.currentStreak = 1; // 首次签到
        }

        _signInData.lastSignInDate = now.ToString("O");
        GrantReward();
        SaveData();
    }

}

public class SignInUI : MonoBehaviour
{
    public void OnSignInButtonClicked()
    {
        if (SignInManager.Instance.CanSignIn())
        {
            SignInManager.Instance.SignIn();
        }
        else
        {
            Debug.Log("今日已签到或未到签到时间!");
        }
    }
}