问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Unity实现日夜交替效果详解

创作时间:
作者:
@小白创作中心

Unity实现日夜交替效果详解

引用
51CTO
1.
https://blog.51cto.com/u_16213662/12928413

本文将介绍如何在Unity中实现日夜交替效果。通过本教程,你将学习到如何使用Universal RP插件、编写相关脚本以及搭建场景来实现这一效果。

一、效果展示

(此处应有效果展示图片,但原文中未提供具体图片)

二、前期准备

1、创建一个2D的项目

2、下载Universal RP插件(Window->Package Manager)

3、添加渲染器



三、场景搭建

四、代码

1、WorldTimeConstants.cs(用来存储公共变量)

public static class WorldTimeConstants
{
    public const int MinutesInDay = 1440;  //一天一共有多少分钟
}

2、WorldTime.cs(挂载在空物体上)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;  //引入命名空间
public class WorldTime : MonoBehaviour
{
    public event EventHandler<TimeSpan> WorldTimeChanged;  //事件
    [SerializeField]  //用于使私有字段也能在Inspector中显示
    private float _dayLength;
    private TimeSpan _currentTime;
    private float _minuteLength => _dayLength / WorldTimeConstants.MinutesInDay;
    private void Start()
    {
        StartCoroutine(AddMinute());
    }
    private IEnumerator AddMinute()
    {
        _currentTime += TimeSpan.FromMinutes(1);
        WorldTimeChanged?.Invoke(this, _currentTime);  //通知其他脚本游戏时间已经发生了变化
        yield return new WaitForSeconds(_minuteLength);  //用于每隔一定时间(_minuteLength)将游戏世界的时间增加一分钟
        StartCoroutine(AddMinute());  //实现循环增加游戏时间的效果
    }
}

3、WorldTimeDisplay.cs(挂载在时间文本上)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
![](https://wy-static.wenxiaobai.com/chat-rag-image/13829920502532378259)
using System;
/// <summary>
/// 表示在挂载该脚本的 GameObject 上必须要有一个 TMP_Text 组件,
/// 否则会自动添加一个。这样就保证了在使用该脚本时,TMP_Text 组件一定存在,
/// 避免了在运行时出现空引用的情况。
/// </summary>
[RequireComponent(typeof(TMP_Text))]
public class WorldTimeDisplay : MonoBehaviour
{
    [SerializeField]
    private WorldTime _worldTime;
    private TMP_Text _text;
    private void Awake()
    {
        _text = GetComponent<TMP_Text>();
        _worldTime.WorldTimeChanged += OnWorldTimeChanged;  //订阅事件
    }
    private void OnDestroy()
    {
        _worldTime.WorldTimeChanged -= OnWorldTimeChanged;  //取消订阅
    }
    private void OnWorldTimeChanged(object sender, TimeSpan newTime)
    {
        _text.SetText(newTime.ToString(@"hh\:mm"));
    }
}

4、WorldLight.cs(挂载在光源上)

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Experimental.Rendering.Universal;  //需导入资源Universal RP
[RequireComponent(typeof(Light2D))]
public class WorldLight : MonoBehaviour
{
    private Light2D _light;
    [SerializeField]
![](https://wy-static.wenxiaobai.com/chat-rag-image/15048462372744706586)
    private WorldTime _worldTime;
    [SerializeField]
    private Gradient _gradient;  //用于创建一组渐变色
    private void Awake()
    {
        _light = GetComponent<Light2D>();
        _worldTime.WorldTimeChanged += OnWorldTimeChanged;
    }
    private void OnDestroy()
    {
        _worldTime.WorldTimeChanged -= OnWorldTimeChanged;
    }
    private void OnWorldTimeChanged(object sender, TimeSpan newTime)
    {
        _light.color = _gradient.Evaluate(PercentOfDay(newTime));
    }
    private float PercentOfDay(TimeSpan timeSpan)
    {
        //timeSpan.TotalMinutes表示时间跨度(时间差)所代表的分钟数,返回一个双精度浮点数类型。
        //例如,如果一个 TimeSpan 实例的值为 02:30:00(2 小时 30 分钟),则调用 TotalMinutes 属性将返回 150.0。
        return (float)timeSpan.TotalMinutes % WorldTimeConstants.MinutesInDay / WorldTimeConstants.MinutesInDay;
    }
}

5、WorldTimeWatcher.cs(挂载在图标上)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using UnityEngine.Events;
using System.Linq;
public class WorldTimeWatcher : MonoBehaviour
{
    [SerializeField]
    private WorldTime _worldTime;
    /// <summary>
    /// 用于告诉C#编译器可以对标记为该特性的类、结构体、枚举进行序列化和反序列化操作。
    /// 在Unity中,这个特性常常用于标记自定义的数据结构,
    /// 以便在Inspector面板中可以直接显示和编辑。
    /// </summary>
    [Serializable]
    private class Schedule
    {
![](https://wy-static.wenxiaobai.com/chat-rag-image/17263395710976169504)
        public int Hour;
        public int Minute;
        public UnityEvent _action;
    }
    [SerializeField]
    private List<Schedule> _schedule;
    // Start is called before the first frame update
    void Start()
    {
        _worldTime.WorldTimeChanged += CheckSchedule;
    }
    private void OnDestroy()
    {
        _worldTime.WorldTimeChanged -= CheckSchedule;
    }
    private void CheckSchedule(object sender, TimeSpan newTime)
    {
        //FirstOrDefault 方法,查找 _schedule 列表中第一个满足指定条件的元素
        var schedule =
            _schedule.FirstOrDefault(s =>
            s.Hour == newTime.Hours
            && s.Minute == newTime.Minutes);
        schedule?._action?.Invoke();
    }
}
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号