最終效果
日期季節(jié)控制
public class TimeManager : MonoBehaviour
{
public static TimeManager Instance { get; private set; }
// 定義一個事件,在每天過去時觸發(fā)
public UnityEvent OnDayPass = new UnityEvent();
// 季節(jié)枚舉類型
public enum Season
{
Spring,
Summer,
Fall,
Winter
}
// 當前季節(jié)
public Season currentSeason = Season.Spring;
private int daysPerSeason = 30;//每季天數(shù)
private int daysInCurrentSeason = 1;//當前季節(jié)天數(shù)
//日期枚舉類型
public enum DayOfWeek
{
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
public DayOfWeek currentDayOfWeek = DayOfWeek.Monday;
public int dayInGame = 1;//游戲中的天數(shù)
public int yearInGame = 0;//游戲中的年數(shù)
public TextMeshProUGUI dayUIText;
private void Awake()
{
Instance = this;
}
private void Start()
{
UpdateUI();
}
// 觸發(fā)過渡到下一天的方法
public void TriggerNextDay()
{
// 增加游戲中的天數(shù)和當前季節(jié)的天數(shù)
dayInGame += 1;
daysInCurrentSeason += 1;
currentDayOfWeek = (DayOfWeek)(((int)currentDayOfWeek + 1) % 7);
// 檢查是否當前季節(jié)天數(shù)已達到季節(jié)總天數(shù)
if (daysInCurrentSeason > daysPerSeason)
{
// 切換到下一個季節(jié),并重置季節(jié)天數(shù)計數(shù)
daysInCurrentSeason = 1;
currentSeason = GetNextSeason();
}
// 更新UI顯示,觸發(fā)當天過去事件
UpdateUI();
OnDayPass.Invoke();
}
// 獲取下一個季節(jié)的方法
private Season GetNextSeason()
{
// 計算當前季節(jié)索引和下一個季節(jié)索引
int currentSeasonIndex = (int)currentSeason; // 獲取當前季節(jié)索引
int nextSeasonIndex = (currentSeasonIndex + 1) % 4; // 計算下一個季節(jié)索引
// 如果下一個季節(jié)索引為0(春季),增加游戲年份
if (nextSeasonIndex == 0)
{
yearInGame += 1;
}
// 返回下一個季節(jié)
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;
}
//獲取中文季節(jié)
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"
}
配置不同時間過渡材質(zhì)
新增DayNightSystem,負責管理游戲的晝夜系統(tǒng)
public class DayNightSystem : MonoBehaviour
{
// 控制方向光的引用
public Light directionalLight;
// 一整天的持續(xù)時間(以秒為單位)
public float dayDurationInSeconds = 24.0f; // 調(diào)整一整天的持續(xù)時間(以秒為單位)
// 當前的小時
public int currentHour;
// 當前的分鐘
public int currentMinute;
// 當前時間在一天中所占比例(范圍在0到1之間)
float currentTimeOfDay = 0.35f;
// 存儲不同時間段對應(yīng)的天空盒
public List<SkyboxTimeMapping> timeMappings;
// 用于插值的值(范圍在0到1之間)
float blendedValue = 0.0f;
// 是否鎖定下一個白天觸發(fā)
bool lockNextDayTrigger = false;
// 用于顯示時間的UI元素
public TextMeshProUGUI timeUI;
// 在每幀更新
void Update()
{
// 根據(jù)游戲時間計算當前的時間
currentTimeOfDay += Time.deltaTime / dayDurationInSeconds;
currentTimeOfDay = currentTimeOfDay % 1; // 確保值在0到1之間
// 計算當前的小時
currentHour = Mathf.FloorToInt(currentTimeOfDay * 24);
// 計算當前的分鐘數(shù)
currentMinute = Mathf.FloorToInt(currentTimeOfDay * 1440) % 60; // 一天有 24 小時 * 60 分鐘 = 1440 分鐘
//更新時間UI
timeUI.text = $"{currentHour:D2}:{currentMinute:D2}";
// 更新方向光的旋轉(zhuǎn)
directionalLight.transform.rotation = Quaternion.Euler(new Vector3((currentTimeOfDay * 360) - 90, 170, 0));
// 根據(jù)時間更新天空盒材質(zhì)
UpdateSkybox();
}
// 更新天空盒材質(zhì)的方法
private void UpdateSkybox()
{
// 尋找當前小時對應(yīng)的天空盒材質(zhì)
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;
}
// 如果找到了對應(yīng)的天空盒材質(zhì),則更新RenderSettings的skybox
if (currentSkybox != null)
{
RenderSettings.skybox = currentSkybox;
}
}
}
// 存儲時間和對應(yīng)天空盒材質(zhì)的類
[System.Serializable]
public class SkyboxTimeMapping
{
public string phaseName;
public int hour; // 小時
public Material skyboxMaterial; // 對應(yīng)的天空盒材質(zhì)
}
配置
效果
下雨
下雨粒子效果
這里只做個簡單的,想要更復(fù)雜的下雨效果,可以看我之前的文章:【實現(xiàn)100個unity特效之7】unity 3d實現(xiàn)各種粒子效果
默認禁用雨
控制雨一直跟隨玩家,但是旋轉(zhuǎn)不跟隨
//跟隨玩家
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; // 下雨天氣的天空盒材質(zhì)
public bool isSpecialWeather; // 是否是特殊天氣
public AudioSource rainChannel; // 下雨音效的音頻源
public AudioClip rainSound; // 下雨音效
public enum WeatherCondition
{
Sunny, // 晴天
Rainy, // 下雨
Snowy // 下雪(未在代碼中實現(xiàn))
}
private WeatherCondition currentWeather = WeatherCondition.Sunny; // 當前天氣默認為晴天
private void Start()
{
// 監(jiān)聽一天的流逝事件,用于生成隨機天氣
TimeManager.Instance.OnDayPass.AddListener(GenerateRandomWeather);
}
private void GenerateRandomWeather()
{
TimeManager.Season currentSeason = TimeManager.Instance.currentSeason;
float chanceToRain = 0f;
// 根據(jù)當前季節(jié)設(shè)定下雨概率
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;
}
// 生成一個隨機數(shù),用于判斷是否下雨
if (Random.value < chanceToRain)
{
currentWeather = WeatherCondition.Rainy; // 設(shè)置為下雨天氣
isSpecialWeather = true; // 標記為特殊天氣
Invoke("StartRain", 1f); // 延遲1秒開始下雨效果
}
else
{
currentWeather = WeatherCondition.Sunny; // 設(shè)置為晴天
isSpecialWeather = false; // 標記為非特殊天氣
StopRain(); // 停止下雨效果
}
}
private void StartRain()
{
if (rainChannel.isPlaying == false)
{
rainChannel.clip = rainSound;
rainChannel.loop = true;
rainChannel.Play();
}
RenderSettings.skybox = rainSkyBox; // 切換天空盒為下雨天氣材質(zhì)
rainEffect.SetActive(true); // 激活下雨特效
}
private void StopRain()
{
if (rainChannel.isPlaying)
{
rainChannel.Stop(); // 停止下雨音效
}
rainEffect.SetActive(false); // 關(guān)閉下雨特效
}
}
修改DayNightSystem
public WeatherSystem weatherSystem;
void Update()
{
// 。。。
if (currentHour == 0 && lockNextDayTrigger == false)
{
TimeManager.Instance.TriggerNextDay();
lockNextDayTrigger = true;
}
if (currentHour != 0)
{
lockNextDayTrigger = false;
}
// 根據(jù)時間更新天空盒材質(zhì)
if(weatherSystem.isSpecialWeather == false) UpdateSkybox();
}
// 更新天空盒材質(zhì)的方法
private void UpdateSkybox()
{
// 尋找當前小時對應(yīng)的天空盒材質(zhì)
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;
}
}
// 如果找到了對應(yīng)的天空盒材質(zhì),則更新RenderSettings的skybox
if (currentSkybox != null)
{
RenderSettings.skybox = currentSkybox;
}
}
配置,雨聲我這里就不做配置了
效果
源碼
整理好了我會放上來
完結(jié)
贈人玫瑰,手有余香!如果文章內(nèi)容對你有所幫助,請不要吝嗇你的點贊評論和關(guān)注
,以便我第一時間收到反饋,你的每一次支持
都是我不斷創(chuàng)作的最大動力。當然如果你發(fā)現(xiàn)了文章中存在錯誤
或者有更好的解決方法
,也歡迎評論私信告訴我哦!
好了,我是向宇
,https://xiangyu.blog.csdn.net
一位在小公司默默奮斗的開發(fā)者,出于興趣愛好,最近開始自學unity,閑暇之余,邊學習邊記錄分享,站在巨人的肩膀上,通過學習前輩們的經(jīng)驗總是會給我很多幫助和啟發(fā)!php是工作,unity是生活!如果你遇到任何問題,也歡迎你評論私信找我, 雖然有些問題我也不一定會,但是我會查閱各方資料,爭取給出最好的建議,希望可以幫助更多想學編程的人,共勉~文章來源:http://www.zghlxwxcb.cn/news/detail-842745.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-842745.html
到了這里,關(guān)于【unity實戰(zhàn)】時間控制 晝夜交替 四季變化 天氣變化效果的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!