Unistorm是Unity中的一个天气系统,它功能强大,效果优美。本文所述UniStorm为3.0版本,仅用于学习之用。
在Running模式下,按下Esc按键,会【弹出】或者【隐藏】天气设置界面
有时候,用户操作的慢了,天气突然从白天变成黑夜,乌漆嘛黑的伸手不见五指。为了防止这种尴尬,所以有时候需要关闭时间流淌的功能。
【UniStorm System】->【Time】->【Time Flow】 设置成[Disabled]
需求:UniStorm中的天空盒是一个半球,如果要模拟飞机在云团中穿行,那么需要一整个球把飞机包住。
解决:在运行状态下,再复制出一个天气半球,并设置两个半球是合在一起的。
(1)云层的天空半球
///
/// 云层组件
///
[Header("云层组件")]
public GameObject UniStormClouds;
(2)复制天空半球,设置对原来的球的对面,让两个半球合拢成一个球。
参数为硬编码,提前在Editor的running模式下,手工操作一遍,然后保存这些参数。
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】,把这个脚本禁用即可。
天气系统自带的【相机旋转功能】可能会与【祖传的角色控制功能】冲突,所以需要禁用。
场景初始化之后,会自动生成一个叫【UniStorm Canvas】的UI界面。
//等待几秒初始化后,找到UniStorm Canvas组件,然后隐藏
var UniStormCanvas = GameObject.FindObjectsOfType<Canvas>(true).First(x => x.name == "UniStorm Canvas");
UniStormCanvas.gameObject.SetActive(false);
///
/// 获取设置天气的三个UI元素
/// 时辰-slider
/// 天气类型-dropdownList
/// 确定更改-button
///
///
///
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事件。
#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 System】物体上有一个叫UniStormSystem的主脚本
【UniStorm Demo Player】物体和它的子物体下面有一些相机对应的功能
如果要读源码应该从UniStormSystem.cs下手
namespace AsyncStep
{
///
/// 获取天气设置的组件
///
public class SetWeatherV3 : MonoBehaviour
{
///
/// 云层组件
///
[Header("云层组件")] public GameObject UniStormClouds;
///
/// 效果相机
///
[Header("效果相机")] public Camera effectCamera;
///
/// 地形
///
[Header("地形")] public Terrain MyTerrain;
///
/// 天气系统主脚本
///
[Header("天气系统主脚本")] public UniStormSystem unistorm;
///
/// 天气类型
///
[Header("天气类型-测试用")]public string weatherType = "Thunderstorm";
///
/// 时间设置
///
[Header("======运行时自动获取UI组件======")] [Header("时间设置")]
public Slider TimeSlider;
///
/// 天气种类
///
[Header("天气种类")] public Dropdown WeatherDropdown;
///
/// 确认按钮
///
[Header("确认按钮")] public Button ChangeWeatherBtn;
void Start()
{
GetUiElements(this.GetCancellationTokenOnDestroy());
}
///
/// 获取设置天气的三个UI元素
/// 时辰-slider
/// 天气类型-dropdownList
/// 确定更改-button
///
///
///
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();
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using UnityEngine;
using static txlib;
namespace AsyncStep
{
///
/// 天气控制:天气类型 + 日期时刻
///
public class SetWeatherInfoControl : MonoBehaviour, IFlowAsync
{
///
/// 天气组件
///
[Header("天气组件")] public SetWeatherV3 weather;
///
/// 时间点
///
[Header("时间点")] public float sliderValue;
///
/// 天气类型
///
[Header("天气类型")] public string weatherType;
///
/// 本步骤的名字:Start中预先缓存,防止报空
///
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} 执行完毕");
}
}
}