首页 > 其他分享 >【unity实战】时间控制 昼夜交替 四季变化 天气变化效果

【unity实战】时间控制 昼夜交替 四季变化 天气变化效果

时间:2024-03-21 10:30:38浏览次数:27  
标签:实战 case Season 下雨 private break unity 变化 public

最终效果

在这里插入图片描述

文章目录

日期季节控制

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是生活!如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~

在这里插入图片描述

标签:实战,case,Season,下雨,private,break,unity,变化,public
From: https://blog.csdn.net/qq_36303853/article/details/136790716

相关文章

  • 尚硅谷Vue3入门到实战,最新版vue3+TypeScript前端开发教程
    1.创建Vue3工程npmcreatevue@latest或者npminitvue@latest输入项目名和需要的工具后进入项目如果项目报错使用命令安装Node.js的项目依赖包npmi启动vue项目,查看项目是否创建完成npmrundev直接删掉src然后创建src文件夹,在该文件夹中创建main.ts和App.vue文件......
  • 一学就会 | ChatGPT提示词-[简历指令库]-有爱AI实战教程(八)
    演示站点:  https://ai.uaai.cn 对话模块官方论坛:  www.jingyuai.com 京娱AI 一、导读:在使用ChatGPT时,当你给的指令越精确,它的回答会越到位,举例来说,假如你要请它帮忙写文案,如果没给予指定情境与对象,它会不知道该如何回答的更加准确。当你看到199的教程时,......
  • 性能测试实战系列(02):性能测试需求
     本系列汇总,请查看这里:https://www.cnblogs.com/uncleyong/p/15475614.html说明性能测试需求不是性能测试人员给出的,如果项目组没人能给出,性能测试人员可以引导,不同项目有不同的方案:迭代项目通过efk统计:https://www.cnblogs.com/uncleyong/p/15527484.html......
  • 性能测试实战系列(01):项目简介
     本系列汇总,请查看这里:https://www.cnblogs.com/uncleyong/p/15475614.html项目简介、背景略(后续完善) 项目架构礼品兑换中心微服务架构示意图(部分展示): 微服务项目开发、调试项目开发:略 另外,本地开发调试代码需要用到skywalking,方便查看调用链路:https://www.cnblog......
  • 性能测试实战系列(15):准备压测脚本、数据
     本系列汇总,请查看这里:https://www.cnblogs.com/uncleyong/p/15475614.html脚本查询礼品 兑换礼品 查询订单 其它设置http请求默认值  响应断言 后端监听器 数据库存量数据礼品:10000,在05章节已经通过存储过程造存量数据库存:10000,在05章节已经通过......
  • 性能测试实战系列(18):压测执行 - 容量场景(含监控、分析、调优、回归)
     本系列汇总,请查看这里:https://www.cnblogs.com/uncleyong/p/15475614.html测试执行根据容量场景设计,非gui执行脚本。 结果12线程  监控(部分) 性能问题:锁使用不合理待更新... ......
  • 性能测试实战系列(19):压测执行 - 稳定性场景(含监控、分析、调优、回归)
     本系列汇总,请查看这里:https://www.cnblogs.com/uncleyong/p/15475614.html测试执行根据稳定性场景设计,非gui执行脚本。 结果说明:下图大概00:25后tps上升,是因为我把服务器上无关的服务停了 结论达到压测目标 ......
  • Spring boot2.7整合jetcache方法缓存 处理数据发生变化时同步更新缓存 删除缓存操作
    上文Springboot2.7整合jetcache方法缓存我们做了个方法缓存的案例可以将接口内容缓存起来是能大大提高效率的但是我们接口的数据大多来自数据库如果我们调用增删查改它的数据变化了那缓存的内容就会因为没有及时更新变的不准确例如我们这样我们在上面定义了......
  • 【云原生 • Kubernetes】认识 k8s、k8s 架构、核心实战
    文章目录Kubernetes基础概念1.是什么2.架构2.1工作方式2.2组件架构3.k8s组件创建集群步骤一基础环境步骤二安装kubelet、kubeadm、kubectl步骤三主节点使用kubeadm引导集群步骤四副节点加入主节点步骤五部署dashboardKubernetes核心实战1.资源创建方式2.N......
  • 【飞浆AI实战】交通灯检测:手把手带你入门PaddleDetection,从训练到部署
    前言本次分享将带领大家从0到1完成一个目标检测任务的模型训练评估和推理部署全流程,项目将采用以PaddleDetection为核心的飞浆深度学习框架进行开发,并总结开发过程中踩过的一些坑,希望能为有类似项目需求的同学提供一点帮助。项目背景和目标背景:目标检测是计算机视觉的一......