Unity中的Unistorm3.0天气系统笔记

Unistorm是Unity中的一个天气系统,它功能强大,效果优美。本文所述UniStorm为3.0版本,仅用于学习之用。

一、如何设置【白天】、【黑夜】和【天气类型】?

在Running模式下,按下Esc按键,会【弹出】或者【隐藏】天气设置界面

  • 第一个滑动条为:当下的时辰【对应从早到晚的进度】
  • 第二个下拉框为:天气的类型
  • 第三个按钮:确定按钮

二、如何禁用时间流淌(Time Flow)功能?

有时候,用户操作的慢了,天气突然从白天变成黑夜,乌漆嘛黑的伸手不见五指。为了防止这种尴尬,所以有时候需要关闭时间流淌的功能。

【UniStorm System】->【Time】->【Time Flow】 设置成[Disabled]

三、模拟飞机在云团中穿行时,如何制作一个全景包围球?

需求:UniStorm中的天空盒是一个半球,如果要模拟飞机在云团中穿行,那么需要一整个球把飞机包住。

解决:在运行状态下,再复制出一个天气半球,并设置两个半球是合在一起的。

(1)云层的天空半球

csharp 复制代码
/// <summary>
/// 云层组件
/// </summary>
[Header("云层组件")]
public GameObject UniStormClouds;

(2)复制天空半球,设置对原来的球的对面,让两个半球合拢成一个球。

参数为硬编码,提前在Editor的running模式下,手工操作一遍,然后保存这些参数。

csharp 复制代码
private void CreateUniStormClouds()
{
    var uniStormCloudsClone = GameObject.Instantiate(UniStormClouds);
    uniStormCloudsClone.transform.parent = UniStormClouds.transform.parent;
    uniStormCloudsClone.transform.localPosition = new Vector3(-0.06383133f, -293f, -223f);
    uniStormCloudsClone.transform.rotation = Quaternion.Euler(90, 0, 0);
    uniStormCloudsClone.transform.localScale = new Vector3(1000000, 1000001, 700000);
}

四、如何关闭鼠标控制相机转动的功能

相机上挂在了一个脚本【Pause】,把这个脚本禁用即可。

天气系统自带的【相机旋转功能】可能会与【祖传的角色控制功能】冲突,所以需要禁用。

五、按【Esc】键的时候,天气设置界面不再显示和隐藏,如何实现?

场景初始化之后,会自动生成一个叫【UniStorm Canvas】的UI界面。

(1)简单粗暴的解决方法:在启动的时候,抓取这个对象,然后把他们隐藏掉。

csharp 复制代码
	//等待几秒初始化后,找到UniStorm Canvas组件,然后隐藏
	var UniStormCanvas = GameObject.FindObjectsOfType<Canvas>(true).First(x => x.name == "UniStorm Canvas");
	 UniStormCanvas.gameObject.SetActive(false);

(2)最优的实现:插件已经提供这个功能的【启用】和【禁用】参数了

(3)正常的操作就是先找到UI,然后在关闭该选项

csharp 复制代码
/// <summary>
/// 获取设置天气的三个UI元素
///     时辰-slider
///     天气类型-dropdownList
///     确定更改-button
/// </summary>
/// <param name="ctk"></param>
/// <returns></returns>
private async UniTask GetUiElements(CancellationToken ctk)
{
    //【1】等待一段时间进行初始化
    await UniTask.DelayFrame(2,cancellationToken:ctk);

    //【2】获取用来设置天气的3个UI组件
    var UniStormCanvas = GameObject.FindObjectsOfType<Canvas>(true).First(x => x.name == "UniStorm Canvas");
    TimeSlider = UniStormCanvas.GetComponentsInChildren<Slider>(true).Where(x => x.name == "Time Slider")
        .First();
    WeatherDropdown = UniStormCanvas.GetComponentsInChildren<Dropdown>(true)
        .Where(x => x.name == "Weather Dropdown").First();
    ChangeWeatherBtn = UniStormCanvas.GetComponentsInChildren<Button>(true)
        .Where(x => x.name == "Change Weather Button").First();

    //【3】关闭设置菜单
    unistorm.UseUniStormMenu = UniStormSystem.EnableFeature.Disabled;
}

六、如何通过代码更换天气

在不破坏UniStorm工程文件的前提下,思路:

1、在运行时获取设置天气的UI元素,

2、赋值【时辰】和【天气类型】,激发【确定】按钮的click事件。

csharp 复制代码
#if UNITY_EDITOR
[ContextMenu("天气设置")]
#endif
async UniTask test4()
{
	Setweather();
}

private async UniTask Setweather()
{
	await UniTask.Delay(TimeSpan.FromSeconds(2f));
	
	//找到组件
	var UniStormCanvas = GameObject.FindObjectsOfType<Canvas>(true).First(x => x.name == "UniStorm Canvas");
	Debug.Log(UniStormCanvas);
	TimeSlider = UniStormCanvas.GetComponentsInChildren<Slider>(true).Where(x => x.name == "Time Slider").First();
	WeatherDropdown = UniStormCanvas.GetComponentsInChildren<Dropdown>(true).Where(x => x.name == "Weather Dropdown").First();
	ChangeWeatherBtn = UniStormCanvas.GetComponentsInChildren<Button>(true).Where(x => x.name == "Change Weather Button").First();
	
	//设置value
	TimeSlider.value = 0.5f;
	WeatherDropdown.SetOption("Thunderstorm");
	ChangeWeatherBtn.onClick.Invoke();
}

七、UniStorm的主要入口脚本

【UniStorm System】物体上有一个叫UniStormSystem的主脚本

【UniStorm Demo Player】物体和它的子物体下面有一些相机对应的功能

如果要读源码应该从UniStormSystem.cs下手

八、附录------天气控制的脚本

(1)获取天空半球,获取设置天气的UI元素,简单设置天气

csharp 复制代码
namespace AsyncStep
{
    /// <summary>
    /// 获取天气设置的组件
    /// </summary>
    public class SetWeatherV3 : MonoBehaviour
    {
        /// <summary>
        /// 云层组件
        /// </summary>
        [Header("云层组件")] public GameObject UniStormClouds;

        /// <summary>
        /// 效果相机
        /// </summary>
        [Header("效果相机")] public Camera effectCamera;

        /// <summary>
        /// 地形
        /// </summary>
        [Header("地形")] public Terrain MyTerrain;

        /// <summary>
        /// 天气系统主脚本
        /// </summary>
        [Header("天气系统主脚本")] public UniStormSystem unistorm;

        /// <summary>
        /// 天气类型
        /// </summary>
        [Header("天气类型-测试用")]public string weatherType = "Thunderstorm";

        /// <summary>
        /// 时间设置
        /// </summary>
        [Header("======运行时自动获取UI组件======")] [Header("时间设置")]
        public Slider TimeSlider;

        /// <summary>
        /// 天气种类
        /// </summary>
        [Header("天气种类")] public Dropdown WeatherDropdown;

        /// <summary>
        /// 确认按钮
        /// </summary>
        [Header("确认按钮")] public Button ChangeWeatherBtn;

        void Start()
        {
            GetUiElements(this.GetCancellationTokenOnDestroy());
        }

        /// <summary>
        /// 获取设置天气的三个UI元素
        ///     时辰-slider
        ///     天气类型-dropdownList
        ///     确定更改-button
        /// </summary>
        /// <param name="ctk"></param>
        /// <returns></returns>
        private async UniTask GetUiElements(CancellationToken ctk)
        {
            //【1】等待一段时间进行初始化
            await UniTask.DelayFrame(2,cancellationToken:ctk);

            //【2】获取用来设置天气的3个UI组件
            var UniStormCanvas = GameObject.FindObjectsOfType<Canvas>(true).First(x => x.name == "UniStorm Canvas");
            TimeSlider = UniStormCanvas.GetComponentsInChildren<Slider>(true).Where(x => x.name == "Time Slider")
                .First();
            WeatherDropdown = UniStormCanvas.GetComponentsInChildren<Dropdown>(true)
                .Where(x => x.name == "Weather Dropdown").First();
            ChangeWeatherBtn = UniStormCanvas.GetComponentsInChildren<Button>(true)
                .Where(x => x.name == "Change Weather Button").First();

            //【3】关闭设置菜单
            unistorm.UseUniStormMenu = UniStormSystem.EnableFeature.Disabled;
        }

#if UNITY_EDITOR
        [ContextMenu("天气设置")]
#endif
        async UniTask test4()
        {
            Setweather();
        }

        private async UniTask Setweather()
        {
            //设置value
            TimeSlider.value = 0.5f;
            WeatherDropdown.SetOption(weatherType);
            ChangeWeatherBtn.onClick.Invoke();
        }
    }
}

(2)设置天气类型

csharp 复制代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using UnityEngine;
using static txlib;

namespace AsyncStep
{
    /// <summary>
    /// 天气控制:天气类型 + 日期时刻
    /// </summary>
    public class SetWeatherInfoControl : MonoBehaviour, IFlowAsync
    {
        /// <summary>
        /// 天气组件
        /// </summary>
        [Header("天气组件")] public SetWeatherV3 weather;

        /// <summary>
        /// 时间点
        /// </summary>
        [Header("时间点")] public float sliderValue;

        /// <summary>
        /// 天气类型
        /// </summary>
        [Header("天气类型")] public string weatherType;

        /// <summary>
        /// 本步骤的名字:Start中预先缓存,防止报空
        /// </summary>
        public string this_name;

        // Start is called before the first frame update
        void Start()
        {
            this_name = this.name;
        }

#if UNITY_EDITOR
        [ContextMenu("测试")]
#endif
        void Test()
        {
            FlowAsync(this.GetCancellationTokenOnDestroy());
        }

        public async UniTask FlowAsync(CancellationToken ctk)
        {
            try
            {
                weather.TimeSlider.value = sliderValue;
                Debug.Log(weather.TimeSlider.value);

                //设置value
                weather.TimeSlider.value = sliderValue;
                weather.WeatherDropdown.SetOption(weatherType);
                weather.ChangeWeatherBtn.onClick.Invoke();
            }
            catch (Exception e)
            {
                Debug.Log($"{this_name}报错:{e.Message}");
                Debug.Log($"\n 抛出一个OperationCanceledException");
                throw new OperationCanceledException();
            }

            Debug.Log($"{this.name} 执行完毕");
        }
    }
}
相关推荐
在路上看风景1 天前
15. 纹理尺寸是4的倍数
unity
AT~1 天前
unity 使用Socket和protobuf实现网络连接
unity·游戏引擎
怣疯knight2 天前
Cocos creator判断节点是否能用的方法
unity·cocos2d
tealcwu2 天前
Google Play的Keystore不可用时的解决方法
unity
呼呼突突2 天前
Unity使用TouchSocket的RPC
unity·rpc·游戏引擎
qq 180809512 天前
从零构建一个多目标多传感器融合跟踪器
unity
平行云2 天前
实时云渲染支持在网页上运行UE5开发的3A大作Lyra项目
unity·云原生·ue5·webgl·虚拟现实·实时云渲染·像素流送
鹏飞于天2 天前
Shader compiler initialization error: Failed to read D3DCompiler DLL file
unity
wonder135792 天前
UGUI重建流程和优化
unity·游戏开发·ugui
那个村的李富贵2 天前
Unity打包Webgl后 本地运行测试
unity·webgl