最终效果

在这里插入图片描述

日期季节控制

public class TimeManager : MonoBehaviour
{
    public static TimeManager Instance { get; private set; }

    // 定义一个事件,在每天过去时触发
    public UnityEvent OnDayPass = new UnityEvent();

    // 季节枚举类型
    public enum Season
    {
        Spring,
        Summer,
        Fall, 
        Winter
    }

    // 当前季节
    public Season currentSeason = Season.Spring;
    private int daysPerSeason = 30;//每季天数
    private int daysInCurrentSeason = 1;//当前季节天数

    //日期枚举类型
    public enum DayOfWeek
    {
        Monday,
        Tuesday,
        Wednesday,
        Thursday,
        Friday,
        Saturday,
        Sunday
    }
    public DayOfWeek currentDayOfWeek = DayOfWeek.Monday;

    public int dayInGame = 1;//游戏中的天数
    public int yearInGame = 0;//游戏中的年数
    public TextMeshProUGUI dayUIText;

    private void Awake()
    {
        Instance = this;
    }

    private void Start()
    {
        UpdateUI();
    }

    // 触发过渡到下一天的方法
    public void TriggerNextDay()
    {
        // 增加游戏中的天数和当前季节的天数
        dayInGame += 1;
        daysInCurrentSeason += 1;

        currentDayOfWeek = (DayOfWeek)(((int)currentDayOfWeek + 1) % 7);

        // 检查是否当前季节天数已达到季节总天数
        if (daysInCurrentSeason > daysPerSeason)
        {
            // 切换到下一个季节,并重置季节天数计数
            daysInCurrentSeason = 1;
            currentSeason = GetNextSeason();
        }

        // 更新UI显示,触发当天过去事件
        UpdateUI();
        OnDayPass.Invoke();
    }

    // 获取下一个季节的方法
    private Season GetNextSeason()
    {
        // 计算当前季节索引和下一个季节索引
        int currentSeasonIndex = (int)currentSeason; // 获取当前季节索引
        int nextSeasonIndex = (currentSeasonIndex + 1) % 4; // 计算下一个季节索引

        // 如果下一个季节索引为0(春季),增加游戏年份
        if (nextSeasonIndex == 0)
        {
            yearInGame += 1;
        }

        // 返回下一个季节
        return (Season)nextSeasonIndex;
    }

    // 更新UI显示的方法
    private void UpdateUI()
    {
        string currentDayOfWeekChinese = getCurrentDayOfWeekChinese(currentDayOfWeek);
        string currentSeasonChinese = getCurrentSeasonChinese(currentSeason);
        dayUIText.text = $"{currentDayOfWeekChinese}{daysInCurrentSeason} 天,{currentSeasonChinese}";
    }

    //获取中文日期
    private string getCurrentDayOfWeekChinese(DayOfWeek currentDayOfWeek)
    {
        string currentDayOfWeekChinese = "";
        switch (currentDayOfWeek)
        {
            case DayOfWeek.Monday:
                currentDayOfWeekChinese = "星期一";
                break;
            case DayOfWeek.Tuesday:
                currentDayOfWeekChinese = "星期二";
                break;
            case DayOfWeek.Wednesday:
                currentDayOfWeekChinese = "星期三";
                break;
            case DayOfWeek.Thursday:
                currentDayOfWeekChinese = "星期四";
                break;
            case DayOfWeek.Friday:
                currentDayOfWeekChinese = "星期五";
                break;
            case DayOfWeek.Saturday:
                currentDayOfWeekChinese = "星期六";
                break;
            case DayOfWeek.Sunday:
                currentDayOfWeekChinese = "星期日";
                break;
            default:
                break;
        }
        return currentDayOfWeekChinese;
    }

    //获取中文季节
    private string getCurrentSeasonChinese(Season currentSeason)
    {
        string currentSeasonChinese = "";
        switch (currentSeason)
        {
            case Season.Spring:
                currentSeasonChinese = "春";
                break;
            case Season.Summer:
                currentSeasonChinese = "夏";
                break;
            case Season.Fall:
                currentSeasonChinese = "秋";
                break;
            case Season.Winter:
                currentSeasonChinese = "冬";
                break;
            default:
                break;
        }
        return currentSeasonChinese;
    }
}

配置
在这里插入图片描述
效果
在这里插入图片描述

时间昼夜交替

素材

https://assetstore.unity.com/packages/2d/textures-materials/sky/fantasy-skybox-free-18353
在这里插入图片描述

如果没有天空盒,需要自己配置

在这里插入图片描述
在这里插入图片描述

新增SkyboxBlendingShader.shader,控制天空盒平滑过渡交替变化

Shader "Custom/SkyboxTransition"
{
    Properties
    {
        _TransitionFactor("Transition Factor", Range(0, 1)) = 0.0
        _AtmosphereTex("Atmosphere CubeMap", Cube) = "" {}
        _SpaceTex("Space CubeMap", Cube) = "" {}
    }

    SubShader
    {
        Tags { "Queue"="Background" }
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata_t
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float3 pos : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            float _TransitionFactor;
            samplerCUBE _AtmosphereTex;
            samplerCUBE _SpaceTex;

            v2f vert(appdata_t v)
            {
                v2f o;
                o.pos = v.vertex.xyz;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }

            half4 frag(v2f i) : SV_Target
            {
                // Use the transition factor to blend between the two skybox cube maps
                half4 atmosphereColor = texCUBE(_AtmosphereTex, i.pos);
                half4 spaceColor = texCUBE(_SpaceTex, i.pos);
                half4 finalColor = lerp(atmosphereColor, spaceColor, _TransitionFactor);

                return finalColor;
            }
            ENDCG
        }
    }
    FallBack "Skybox/Cubemap"
}

配置不同时间过渡材质
在这里插入图片描述
新增DayNightSystem,负责管理游戏的昼夜系统

public class DayNightSystem : MonoBehaviour
{
    // 控制方向光的引用
    public Light directionalLight;

    // 一整天的持续时间(以秒为单位)
    public float dayDurationInSeconds = 24.0f; // 调整一整天的持续时间(以秒为单位)

    // 当前的小时
    public int currentHour;
    // 当前的分钟
    public int currentMinute;

    // 当前时间在一天中所占比例(范围在0到1之间)
    float currentTimeOfDay = 0.35f;

    // 存储不同时间段对应的天空盒
    public List<SkyboxTimeMapping> timeMappings;

    // 用于插值的值(范围在0到1之间)
    float blendedValue = 0.0f;

    // 是否锁定下一个白天触发
    bool lockNextDayTrigger = false;

    // 用于显示时间的UI元素
    public TextMeshProUGUI timeUI;

    // 在每帧更新
    void Update()
    {
        // 根据游戏时间计算当前的时间
        currentTimeOfDay += Time.deltaTime / dayDurationInSeconds;
        currentTimeOfDay = currentTimeOfDay % 1; // 确保值在0到1之间

        // 计算当前的小时
        currentHour = Mathf.FloorToInt(currentTimeOfDay * 24);
        // 计算当前的分钟数
        currentMinute = Mathf.FloorToInt(currentTimeOfDay * 1440) % 60; // 一天有 24 小时 * 60 分钟 = 1440 分钟
        //更新时间UI
        timeUI.text = $"{currentHour:D2}:{currentMinute:D2}";

        // 更新方向光的旋转
        directionalLight.transform.rotation = Quaternion.Euler(new Vector3((currentTimeOfDay * 360) - 90, 170, 0));

        // 根据时间更新天空盒材质
        UpdateSkybox();
    }

    // 更新天空盒材质的方法
    private void UpdateSkybox()
    {
        // 寻找当前小时对应的天空盒材质
        Material currentSkybox = null;
        foreach (SkyboxTimeMapping mapping in timeMappings)
        {
            if (currentHour == mapping.hour)
            {
                currentSkybox = mapping.skyboxMaterial;
                if (currentSkybox.shader != null)
                {
                    if (currentSkybox.shader.name == "Custom/SkyboxTransition")
                    {
                        blendedValue += Time.deltaTime;
                        blendedValue = Mathf.Clamp01(blendedValue);
                        currentSkybox.SetFloat("_TransitionFactor", blendedValue);
                    }
                    else
                    {
                        blendedValue = 0;
                    }
                }
                break;
            }
        }
        if (currentHour == 0 && lockNextDayTrigger == false)
        {
            TimeManager.Instance.TriggerNextDay();
            lockNextDayTrigger = true;
        }
        if (currentHour != 0)
        {
            lockNextDayTrigger = false;
        }

        // 如果找到了对应的天空盒材质,则更新RenderSettings的skybox
        if (currentSkybox != null)
        {
            RenderSettings.skybox = currentSkybox;
        }
    }
}

// 存储时间和对应天空盒材质的类
[System.Serializable]
public class SkyboxTimeMapping
{
    public string phaseName;
    public int hour; // 小时
    public Material skyboxMaterial; // 对应的天空盒材质
}

配置
在这里插入图片描述

效果
在这里插入图片描述

下雨

下雨粒子效果

这里只做个简单的,想要更复杂的下雨效果,可以看我之前的文章:【实现100个unity特效之7】unity 3d实现各种粒子效果

在这里插入图片描述
在这里插入图片描述
默认禁用雨
在这里插入图片描述

控制雨一直跟随玩家,但是旋转不跟随

//跟随玩家
public class FollowPlayer : MonoBehaviour
{
    public Transform player;
    public Vector3 offset;
    private void LateUpdate()
    {
        if (player != null)
        {
            Vector3 targetPosition = player.position + offset;
            transform.position = targetPosition;
        }
    }
}

配置
在这里插入图片描述

控制不同天气

新增WeatherSystem

public class WeatherSystem : MonoBehaviour
{
    [Range(0f, 1f)]
    public float chanceToRainSpring = 0.3f; // 春季下雨概率(30%)
    [Range(0f, 1f)]
    public float chanceToRainSummer = 0.7f; // 夏季下雨概率(70%)
    [Range(0f, 1f)]
    public float chanceToRainFall = 0.4f; // 秋季下雨概率(40%)
    [Range(0f, 1f)]
    public float chanceToRainWinter = 0f; // 冬季下雨概率(0%)

    public GameObject rainEffect; // 下雨特效
    public Material rainSkyBox; // 下雨天气的天空盒材质
    public bool isSpecialWeather; // 是否是特殊天气
    public AudioSource rainChannel; // 下雨音效的音频源
    public AudioClip rainSound; // 下雨音效

    public enum WeatherCondition
    {
        Sunny, // 晴天
        Rainy, // 下雨
        Snowy // 下雪(未在代码中实现)
    }

    private WeatherCondition currentWeather = WeatherCondition.Sunny; // 当前天气默认为晴天

    private void Start()
    {
        // 监听一天的流逝事件,用于生成随机天气
        TimeManager.Instance.OnDayPass.AddListener(GenerateRandomWeather);
    }

    private void GenerateRandomWeather()
    {
        TimeManager.Season currentSeason = TimeManager.Instance.currentSeason;
        float chanceToRain = 0f;

        // 根据当前季节设定下雨概率
        switch (currentSeason)
        {
            case TimeManager.Season.Spring:
                chanceToRain = chanceToRainSpring;
                break;
            case TimeManager.Season.Summer:
                chanceToRain = chanceToRainSummer;
                break;
            case TimeManager.Season.Fall:
                chanceToRain = chanceToRainFall;
                break;
            case TimeManager.Season.Winter:
                chanceToRain = chanceToRainWinter;
                break;
        }

        // 生成一个随机数,用于判断是否下雨
        if (Random.value < chanceToRain)
        {
            currentWeather = WeatherCondition.Rainy; // 设置为下雨天气
            isSpecialWeather = true; // 标记为特殊天气
            Invoke("StartRain", 1f); // 延迟1秒开始下雨效果
        }
        else
        {
            currentWeather = WeatherCondition.Sunny; // 设置为晴天
            isSpecialWeather = false; // 标记为非特殊天气
            StopRain(); // 停止下雨效果
        }
    }

    private void StartRain()
    {
        if (rainChannel.isPlaying == false)
        {
            rainChannel.clip = rainSound;
            rainChannel.loop = true;
            rainChannel.Play();
        }
        RenderSettings.skybox = rainSkyBox; // 切换天空盒为下雨天气材质
        rainEffect.SetActive(true); // 激活下雨特效
    }

    private void StopRain()
    {
        if (rainChannel.isPlaying)
        {
            rainChannel.Stop(); // 停止下雨音效
        }
        rainEffect.SetActive(false); // 关闭下雨特效
    }
}

修改DayNightSystem

public WeatherSystem weatherSystem;

void Update()
{
    // 。。。

    if (currentHour == 0 && lockNextDayTrigger == false)
    {
        TimeManager.Instance.TriggerNextDay();
        lockNextDayTrigger = true;
    }
    if (currentHour != 0)
    {
        lockNextDayTrigger = false;
    }

    // 根据时间更新天空盒材质
    if(weatherSystem.isSpecialWeather == false) UpdateSkybox();
}

// 更新天空盒材质的方法
private void UpdateSkybox()
{
    // 寻找当前小时对应的天空盒材质
    Material currentSkybox = null;
    foreach (SkyboxTimeMapping mapping in timeMappings)
    {
        if (currentHour == mapping.hour)
        {
            currentSkybox = mapping.skyboxMaterial;
            if (currentSkybox.shader != null)
            {
                if (currentSkybox.shader.name == "Custom/SkyboxTransition")
                {
                    blendedValue += Time.deltaTime;
                    blendedValue = Mathf.Clamp01(blendedValue);
                    currentSkybox.SetFloat("_TransitionFactor", blendedValue);
                }
                else
                {
                    blendedValue = 0;
                }
            }
            break;
        }
    }
    // 如果找到了对应的天空盒材质,则更新RenderSettings的skybox
    if (currentSkybox != null)
    {
        RenderSettings.skybox = currentSkybox;
    }
}

配置,雨声我这里就不做配置了
在这里插入图片描述

效果
在这里插入图片描述

源码

整理好了我会放上来

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,出于兴趣爱好,最近开始自学unity,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!php是工作,unity是生活!如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~

在这里插入图片描述

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐