农场游戏中的时间管理实例

一、准备工作

在Unity中创建承载日期和时间的文本

二、设置游戏的时间戳
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//标识这个类可以被序列化
[System.Serializable]
public class GameTimestamp
{
    // 游戏时间戳的成员变量
    public int year;
    //季节的枚举类型
    public enum Season { Spring, Summer, Fall, Winter }
    //星期几的枚举类型
    public enum DayOfTheWeek { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }
    public Season season;
    public int day;
    public int hour;
    public int minute;

    // 构造函数1:根据给定的参数创建一个游戏时间戳实例
    public GameTimestamp(int year, Season season, int day, int hour, int minute)
    {
        this.year = year;
        this.season = season;
        this.day = day;
        this.hour = hour;
        this.minute = minute;
    }
    
    // 构造函数2:复制给定的游戏时间戳实例
    public GameTimestamp(GameTimestamp timestamp)
    {
        this.year = timestamp.year;
        this.season = timestamp.season;
        this.day = timestamp.day;
        this.hour = timestamp.hour;
        this.minute = timestamp.minute;
    }
    
    // 更新游戏时钟
    public void UpdateClock()
    {
        minute++;

        if (minute >= 60) { minute = 0; hour++; }
        if (hour >= 24) { hour = 0; day++; }
        if (day > 30)
        {
            day = 1;
            if (season == Season.Winter) { season = Season.Spring; year++; }
            else { season++; }
        }
    }

    // 获得当天是星期几
    public DayOfTheWeek GetDayOfTheWeek()
    {
        int daysPassed = YearsToDays(year) + SeasonsToDays(season) + day;
        int dayIndex = daysPassed % 7;
        return (DayOfTheWeek)dayIndex;
    }

    // 将小时转换为分钟数
    public static int HoursToMinutes(int hour) { return hour * 60; }
    
    // 将天数转换为小时数
    public static int DaysToHours(int days) { return days * 24; }
    
    // 将季节转换为天数
    public static int SeasonsToDays(Season season)
    {
        int seasonIndex = (int)season;
        return seasonIndex * 30;
    }
    
    // 将年份转化为天数
    public static int YearsToDays(int year) { return year * 4 * 30; }

    // 比较两个不同的时间戳的差异
    public static int CompareTimestamp(GameTimestamp timestamp1, GameTimestamp timestamp2)
    {
        int timestamp1Hours = DaysToHours(YearsToDays(timestamp1.year)) + DaysToHours(SeasonsToDays(timestamp1.season) + DaysToHours(timestamp1.day) + timestamp1.hour);
        int timestamp2Hours = DaysToHours(YearsToDays(timestamp2.year)) + DaysToHours(SeasonsToDays(timestamp2.season) + DaysToHours(timestamp2.day) + timestamp2.hour);
        int difference = timestamp1Hours - timestamp2Hours;
        //返回 difference 的绝对值。
        //Mathf.Abs 是 Unity 引擎中的一个数学函数,用于计算一个数的绝对值。
        //在这个脚本中,它用于计算两个时间戳之间的差异,并返回一个非负值
        return Mathf.Abs(difference);
    }
}
三、设置时间流逝逻辑
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TimeManager : MonoBehaviour
{
    // 创建一个单例对象,其他脚本可以通过Instance访问
    public static TimeManager Instance { get; private set; }

    // 当脚本被实例化时调用的方法,用于初始化实例
    private void Awake()
    {
        // 如果Instance已经存在并且不等于当前实例,则销毁当前实例
        if (Instance != null && Instance != this) { Destroy(this); }
        else { Instance = this; }
    }
    //序列化字段
    [SerializeField]
    // 游戏的时间戳
    GameTimestamp timestamp;

    // 游戏的时间缩放比例(时间流逝速度)
    public float timeScale = 1.0f;

    // 游戏开始时调用的方法
    void Start()
    {
        // 初始化时间戳为游戏开始时的时间
        timestamp = new GameTimestamp(0, GameTimestamp.Season.Spring, 1, 6, 0);
        // 开始一个协程来更新游戏时间
        StartCoroutine(TimeUpdate());
    }
    // 游戏时间更新的协程
    IEnumerator TimeUpdate()
    {
        while (true)
        {
            // 每隔1 / timeScale秒执行一次Tick方法
            Tick();
            yield return new WaitForSeconds(1 / timeScale);
        }
    }
    // 每次游戏时间更新时调用的方法
    public void Tick()
    {
        // 更新时间戳
        timestamp.UpdateClock();
    }
}
四、日夜循环
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TimeManager : MonoBehaviour
{
    public static TimeManager Instance { get; private set; }
    private void Awake()
    {
        if (Instance != null && Instance != this) { Destroy(this); }
        else { Instance = this; }
    }

    [SerializeField]
    GameTimestamp timestamp;
    public float timeScale = 1.0f;
    //将一个用于表示白天和黑夜循环的Transform赋值给sunTransform变量,并声明一个ITimeTracker接口类型的列表listeners,用于保存所有注册的时间追踪器。
    [Header("Day and Night cycle")]
    public Transform sunTransform;
    List<ITimeTracker> listeners = new List<ITimeTracker>();

    void Start()
    {
        timestamp = new GameTimestamp(0, GameTimestamp.Season.Spring, 1, 6, 0);
        StartCoroutine(TimeUpdate());
    }
    IEnumerator TimeUpdate()
    {
        while (true)
        {
            Tick();
            yield return new WaitForSeconds(1 / timeScale);
        }
    }
    
    public void Tick()
    {
        //更新时间戳
        timestamp.UpdateClock();
        //通知所有注册的时间追踪器更新时间
        foreach (ITimeTracker listener in listeners)
        {
            listener.ClockUpdate(timestamp);
        }
        //调用UpdateSunMovement方法更新太阳的位置
        UpdateSunMovement();
    }

    void UpdateSunMovement()
    {
        //当前时间
        int timeInMinutes = GameTimestamp.HoursToMinutes(timestamp.hour) + timestamp.minute;
        //计算太阳的角度
        float sunAngle = .25f * timeInMinutes - 90;
        //将太阳角度应用到sunTransform的欧拉角上,实现太阳的运动
        sunTransform.eulerAngles = new Vector3(sunAngle, 0, 0);
    }

    //获取新的时间戳
    public GameTimestamp GetGameTimestamp()
    {
        //返回当前的时间戳
        return new GameTimestamp(timestamp);
    }
    //将一个时间追踪器注册到列表中
    public void RegisterTracker(ITimeTracker listener)
    {
        listeners.Add(listener);
    }
    //将一个时间追踪器从列表中移除
    public void UnregisterTracker(ITimeTracker listener)
    {
        listeners.Remove(listener);
    }
}
五、测试方法
public class PlayerController : MonoBehaviour

void Update()
{
    //测试光线逻辑
    if(Input.GetKey(KeyCode.RightBracket))
    {
        TimeManager.Instance.Tick();
    }
}

按住右方括号,加速时间流速

六、创建接口
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface ITimeTracker 
{
    void ClockUpdate(GameTimestamp timestamp);
}
七、显示游戏时间

1、编辑UIManager.cs,游戏时间

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

//添加接口,管理时间
public class UIManager : MonoBehaviour, ITimeTracker
{
    public static UIManager Instance { get; private set; }
    private void Awake()
    {
        if (Instance != null && Instance != this) { Destroy(this); }
        else { Instance = this; }
    }

    [Header("Startas Bar")]
    //手持工具栏中的时间文本
    public Text timeText;
    public Text dateText;

    private void Start()
    {
        //注册时间跟踪器(将UIManager添加到时间跟踪器的列表中)
        TimeManager.Instance.RegisterTracker(this);
    }

    //处理UI时间回调(回调:在特定的时刻执行自己定义的代码,实现特定的功能)
    //更新游戏中的时钟
    public void ClockUpdate(GameTimestamp timestamp)
    {
        //获取小时和分钟的值
        int hours = timestamp.hour;
        int minutes = timestamp.minute;

        string prefix = "AM ";
        //转换为下午的时间
        if (hours > 12)
        {
            prefix = "PM ";
            hours -= 12;
        }
        timeText.text = prefix + hours + ":" + minutes.ToString("00");
        //获取日期\星期
        int day = timestamp.day;
        string season = timestamp.season.ToString();
        string dayOfTheWeek = timestamp.GetDayOfTheWeek().ToString();

        dateText.text = season + " " + day + " (" + dayOfTheWeek +")";
    }
}

2、赋值

八、把时间系统运用到耕地上

1、编辑TimeManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TimeManager : MonoBehaviour
{
    public static TimeManager Instance { get; private set; }
    private void Awake()
    {
        if (Instance != null && Instance != this) { Destroy(this); }
        else { Instance = this; }
    }

    [SerializeField]
    GameTimestamp timestamp;
    public float timeScale = 1.0f;

    [Header("Day and Night cycle")]
    public Transform sunTransform;
    List<ITimeTracker> listeners = new List<ITimeTracker>();

    void Start()
    {
        timestamp = new GameTimestamp(0, GameTimestamp.Season.Spring, 1, 6, 0);
        StartCoroutine(TimeUpdate());
    }
    IEnumerator TimeUpdate()
    {
        while (true)
        {
            Tick();
            yield return new WaitForSeconds(1 / timeScale);
        }
    }
    public void Tick()
    {
        timestamp.UpdateClock();
        foreach (ITimeTracker listener in listeners)
        {
            listener.ClockUpdate(timestamp);
        }
        UpdateSunMovement();
    }

    void UpdateSunMovement()
    {
        int timeInMinutes = GameTimestamp.HoursToMinutes(timestamp.hour) + timestamp.minute;
        float sunAngle = .25f * timeInMinutes - 90;
        sunTransform.eulerAngles = new Vector3(sunAngle, 0, 0);
    }

    //获取新的时间戳
    public GameTimestamp GetGameTimestamp()
    {
        return new GameTimestamp(timestamp);
    }

    public void RegisterTracker(ITimeTracker listener)
    {
        listeners.Add(listener);
    }
    public void UnregisterTracker(ITimeTracker listener)
    {
        listeners.Remove(listener);
    }
}

2、编辑Land.cs,设置灌溉后土壤变化

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//添加接口
public class Land : MonoBehaviour, ITimeTracker
{
    public enum LandStatus { Soil, Farmland, Watered }
    public LandStatus landStatus;
    public Material soilMat, farmlandMat, wateredMat;
    new Renderer renderer;

    public GameObject select;
    //灌溉时间
    GameTimestamp timeWatered;
    void Start()
    {
        renderer = GetComponent<Renderer>();
        SwitchLandStatus(LandStatus.Soil);
        //select.SetActive(false);
        Select(false);

        //注册时间戳
        TimeManager.Instance.RegisterTracker(this);
    }

    public void SwitchLandStatus(LandStatus statusToSwitch)
    {
        landStatus = statusToSwitch;
        Material materialToSwitch = soilMat;
        switch (statusToSwitch)
        {
            case LandStatus.Soil: materialToSwitch = soilMat; break;
            case LandStatus.Farmland: materialToSwitch = farmlandMat; break;
            //灌溉后土壤状态
            case LandStatus.Watered:
                materialToSwitch = wateredMat;
                //灌溉后流逝的时间
                timeWatered = TimeManager.Instance.GetGameTimestamp();
                break;
        }
        renderer.material = materialToSwitch;
    }
    public void Select(bool toggle)
    {
        select.SetActive(toggle);
    }

    public void Interact()
    {
        ItemData toolSlot = InventoryManager.Instance.equippedTool;
        EquipmentData equipmentTool = toolSlot as EquipmentData;
        if (equipmentTool != null)
        {
            EquipmentData.ToolType toolType = equipmentTool.toolType;

            switch (toolType)
            {
                case EquipmentData.ToolType.Hoe:
                    SwitchLandStatus(LandStatus.Farmland); break;
                case EquipmentData.ToolType.WateringCan:
                    SwitchLandStatus(LandStatus.Watered); break;
            }
        }
    }

    //设置灌溉后土壤的变化
    public void ClockUpdate(GameTimestamp timestamp)
    {
        if (landStatus == LandStatus.Watered)
        {
            int hoursElapsed = GameTimestamp.CompareTimestamp(timeWatered, timestamp);
            Debug.Log(hoursElapsed + "上次灌溉时间");

            if (hoursElapsed > 24)
            {
                SwitchLandStatus(LandStatus.Farmland);
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值