Unity3d 实时天气系统基于UniStorm插件和xx天气API实现(含源码)
前言
实时天气在Unity3d三维数字沙盘中的作用非常重要,它能够增强虚拟环境的真实感和互动性,实时天气数据的应用可以提供更为精准和直观的天气信息支持,如果真实的数据加上特效、声音和模型反馈会提高产品档次,提高真实感。
目前Unity3d虽然没有自带天气系统,不过天气关联的插件也是琳琅满目,这里个人推荐,项目中使用过的UniStorm插件,其提供了天气系统、时间系统(日夜切换),天气过度(动画)、物理效果、音效、多平台支持(pc/移动端/ARVR等),而且它还具有高度可扩展性和自定义性。
有了UniStorm插件的天气系统作为外壳支撑,真实的天气数据使用彩云天气API接入实现,它提供实况数据、分钟级降水、小时级和天级数据、还有天气预警数据。目前我只需要其实际数据接口,注册即送10000/日调用量,这里作为测试和技术研究完全够用。
关注并私信 U3D实时天气 免费获取测试程序(底部公众号)。
效果
实时效果:
大雨
雷雨
雾霾
其他效果:
萤火虫
火暴雨
雷暴雪
晴转阴
实现
这里的实现思路很简单,就是通过天气API接口获取实时的天气数据,通过数据接口返回数据解析出需要的实时数据,将数据显示在UI上,并通过UniStorm插件的UniStormManager管理类直接调用变更天气类型,并同步了三维地图上的天实时气系统效果。本工程基于Unity2019.4.22f1c1实现
UI搭建
这里的UI系统主要是展示一些文字信息:天气、温度、湿度等,接口提供了很多数据,可以按需解析显示。这里的UI简单搭建:
即用于文字显示天气、温度、湿度等,图标显示天气图标,按钮点击同步天气。
经纬度数据
天气数据的获取需要位置信息,数字沙盘大部分都是运行在PC平台上,获取经纬度直接通过设备的GPS并不适用,因为PC通常没有内建的GPS模块,使用外部API或服务来获取基于IP地址的地理位置。这边采用的代码如下(仅供参考,该接口偶尔会请求异常):
//获取ip地址信息
IEnumerator GetIPLocation()
{UnityWebRequest request = UnityWebRequest.Get("https://ipinfo.io/json");yield return request.SendWebRequest();// 检查网络错误或 HTTP 错误if (request.isNetworkError || request.isHttpError)Debug.LogError("请求失败: " + request.error);else{// 解析 JSON 数据string jsonResponse = request.downloadHandler.text;LocationData locationData = JsonUtility.FromJson<LocationData>(jsonResponse);string[] latLong = locationData.loc.Split(',');if (latLong.Length == 2){Latitude = latLong[0];Longitude = latLong[1];Debug.Log("Latitude: " + Latitude + ", Longitude: " + Longitude);}else{Debug.LogWarning("经纬度解析失败!");}}
}
其中返回的json数据类如下:
[System.Serializable]
public class LocationData
{public string ip;public string city;public string region;public string country;public string loc; // "latitude,longitude"
}
天气数据
数据通过接口直接前往api开放平台注册登录,然后创建应用:
创建应用后选择接口类型(天气),应用场景(随便选),填写应用名称后点击创建即可,创建后在应用管理列表能看到Token和用量等信息,Token后续需要使用,还需注意QPS为1,无法支撑请求频繁情况。
请求接口:
curl "https://api.caiyunapp.com/v2.6/TAkhjf8d1nlSlspN/101.6656,39.2072/realtime"
请求代码如下:
IEnumerator GetWeatherInfo(){string url = $"{BaseUrl}/{ApiKey}/{Longitude},{Latitude}/realtime";//Debug.Log("请求地址: " + url);using (UnityWebRequest request = UnityWebRequest.Get(url)){yield return request.SendWebRequest();// 检查网络错误或 HTTP 错误if (request.isNetworkError || request.isHttpError)Debug.LogError("请求失败: " + request.error);else{Debug.Log("请求成功: " + request.downloadHandler.text);}}}
请求返回实时数据结构:
{"status": "ok", // 返回状态 "api_version": "v2.6", // API 版本"api_status": "active", // API 服务状态"lang": "zh_CN", // 返回语言"unit": "metric", // 单位"tzshift": 28800, // 时区偏移"timezone": "Asia/Shanghai", // 时区"server_time": 1640745758,"location": [39.2072, 101.6656],"result": {"realtime": {"status": "ok","temperature": -7, // 地表 2 米气温"humidity": 0.58, // 地表 2 米湿度相对湿度(%)"cloudrate": 0, // 总云量(0.0-1.0)"skycon": "CLEAR_DAY", // 天气现象"visibility": 7.8, // 地表水平能见度"dswrf": 47.7, // 向下短波辐射通量(W/M2)"wind": {"speed": 1.8, // 地表 10 米风速"direction": 22 // 地表 10 米风向},"pressure": 85583.47, // 地面气压"apparent_temperature": -9.9, // 体感温度"precipitation": {"local": {"status": "ok","datasource": "radar","intensity": 0 // 本地降水强度},"nearest": {"status": "ok","distance": 10000, // 最近降水带与本地的距离"intensity": 0 // 最近降水处的降水强度}},"air_quality": {"pm25": 45, // PM25 浓度(μg/m3)"pm10": 49, // PM10 浓度(μg/m3)"o3": 6, // 臭氧浓度(μg/m3)"so2": 8, // 二氧化硫浓度(μg/m3)"no2": 42, // 二氧化氮浓度(μg/m3)"co": 1.1, // 一氧化碳浓度(mg/m3)"aqi": {"chn": 63, // 国标 AQI"usa": 124},"description": {"chn": "良","usa": "轻度污染"}},"life_index": {"ultraviolet": {"index": 3,"desc": "弱" // 参见 [生活指数](tables/lifeindex)},"comfort": {"index": 12,"desc": "湿冷" // 参见 [生活指数](tables/lifeindex)}}},"primary": 0}
}
按这个请求格式,先根据需要的数据新建需要解析的数据结构:
// 定义数据结构(根据彩云天气 API 文档)
[System.Serializable]
public class WeatherData
{public WeatherResult result;
}[System.Serializable]
public class WeatherResult
{public RealtimeWeather realtime;
}[System.Serializable]
public class RealtimeWeather
{public string skycon; // 天气状况public float temperature; // 温度public float humidity; // 湿度public float pressure; // 地面气压
}
天气显示
上一步,通过接口获取了天气实时数据并进行了解析,这一步将通过数据的更新UI和场景中的天气类型。
UI的刷新Text内容直接数据赋值显示即可,图标和天气现象文字需要根据内容做个转换映射。天气现象代码和文字如下:
这里直接将其转为字典(Dictionary)存储,方便天气现象文字获取:
// 天气现象 映射表
private static readonly Dictionary<string, string> SkyconMap = new Dictionary<string, string>{{"CLEAR_DAY", "晴(白天)"},{"CLEAR_NIGHT", "晴(夜间)"},{"PARTLY_CLOUDY_DAY", "多云(白天)"},{"PARTLY_CLOUDY_NIGHT", "多云(夜间)"},{"CLOUDY", "阴"},{"LIGHT_HAZE", "轻度雾霾"},{"MODERATE_HAZE", "中度雾霾"},{"HEAVY_HAZE", "重度雾霾"},{"LIGHT_RAIN", "小雨"},{"MODERATE_RAIN", "中雨"},{"HEAVY_RAIN", "大雨"},{"STORM_RAIN", "暴雨"},{"FOG", "雾"},{"LIGHT_SNOW", "小雪"},{"MODERATE_SNOW", "中雪"},{"HEAVY_SNOW", "大雪"},{"STORM_SNOW", "暴雪"},{"DUST", "浮尘"},{"SAND", "沙尘"},{"WIND", "大风"}
};
关于天气的图标使用的是UniStorm插件内置的图标,正式项目可以让美术搞一套完整的,我这里使用的就是很精简的:
这里的图标没法和天气接口的天气现象一一对应,所以这些图标也需要中间一次转换:
//获取图标类型
string GetIconType(string skycon)
{string icon = "";switch (skycon){case "CLEAR_DAY":case "CLEAR_NIGHT":icon = "clear";break;case "PARTLY_CLOUDY_DAY":case "PARTLY_CLOUDY_NIGHT":icon = "partly_cloudy";break;case "CLOUDY":case "FOG":icon = "cloudy";break;case "LIGHT_HAZE":case "MODERATE_HAZE":case "HEAVY_HAZE":icon = "haze";break;case "LIGHT_RAIN":case "MODERATE_RAIN":icon = "light_rain";break;case "HEAVY_RAIN":case "STORM_RAIN":icon = "heavy_rain";break;case "LIGHT_SNOW":case "MODERATE_SNOW":icon = "light_snow";break;case "HEAVY_SNOW":case "STORM_SNOW":icon = "heavy_snow";break;case "DUST":case "SAND":icon = "sand";break;default:icon = "clear";break;}return icon;
}
如上处理映射了天气现象和需要动态加载的天气图标,更新天气UI的完整代码如下:
//更新天气UI
void UpdateWeatherUI(string jsonData)
{try{// 使用 Unity 内置的 JsonUtility 或第三方 JSON 解析工具(如 Newtonsoft.Json)解析数据WeatherData weatherData = JsonUtility.FromJson<WeatherData>(jsonData);if (weatherData != null && weatherData.result != null){text_skycon.text = "天气:<color=#14FF00>" + (SkyconMap.ContainsKey(weatherData.result.realtime.skycon) ?SkyconMap[weatherData.result.realtime.skycon] : weatherData.result.realtime.skycon) + "</color>";text_temp.text = ($"温度:<color=#14FF00>{weatherData.result.realtime.temperature}℃</color>");text_humidity.text = ($"湿度:<color=#14FF00>{weatherData.result.realtime.humidity * 100}%</color>");text_pressure.text = ($"气压:<color=#14FF00>{weatherData.result.realtime.pressure} Pa</color>");Icon.sprite = Resources.Load<Sprite>("Weather Icons/" + GetIconType(weatherData.result.realtime.skycon));SwitchWeatherType(weatherData.result.realtime.skycon);}else{Debug.LogError("解析天气数据失败");}}catch (Exception e){Debug.LogError($"解析天气数据失败:" + e);}
}
接下来处理三维场景中的天气系统,即将接口返回的天气现象转换到UniStorm插件的天气类型,并进行切换的操作,这里也存在两者之间没法直接一一对应,如下是插件的内置天气类型:
UniStorm插件内置天气类型说明
0 Clear //晴朗
1 Mostly Clear //大部分晴朗
2 Mostly Cloudy //大部分多云
3 Partly Cloudy //局部多云
4 Cloudy //多云
5 Lightning Bugs //萤火虫
6 Blowing Pollen //吹花粉
7 Blowing Leaves //吹落叶
8 Blowing Pine Needles //吹松针
9 Blowing Snow //飞雪
10 Foggy //雾
11 Overcast //阴
12 Hail //冰雹
13 Heavy Rain //暴雨
14 Rain //雨
15 Light Rain //小雨
16 Drizzle //毛毛雨
17 Heavy Snow //大雪
18 Snow //雪
19 Light Snow //小雪
20 Thunderstorm //雷雨
21 Thunder Snow //雷雪
22 Dust Storm //尘暴
23 Fire Rain //火星雨
24 Fire Storm //火星暴雨
这些是在UniStorm System节点上的AllWeatherTypes列表,上面的序号和类型是默认的,它新增了很多创意类型如Fire Rain、Fire Storm和Lightning Bugs等,默认如下:
当然您也可以去新增/修改自己的天气类型,但是如果修改过AllWeatherTypes列表,则没法直接套用。这里的天气映射和切换代码如下:
//切换场景中天气
void SwitchWeatherType(string skycon)
{int idx = 0;switch (skycon){case "CLEAR_DAY":case "CLEAR_NIGHT":idx = 0;break;case "PARTLY_CLOUDY_DAY":case "PARTLY_CLOUDY_NIGHT":idx = 3;break;case "CLOUDY":idx = 2;break;case "FOG":idx = 10;break;case "LIGHT_HAZE":case "MODERATE_HAZE":case "HEAVY_HAZE":idx = 22;break;case "LIGHT_RAIN":idx = 15;break;case "MODERATE_RAIN":idx = 14;break;case "HEAVY_RAIN":case "STORM_RAIN":idx = 13;break;case "LIGHT_SNOW":idx = 19;break;case "MODERATE_SNOW":idx = 18;break;case "HEAVY_SNOW":case "STORM_SNOW":idx = 17;break;case "DUST":case "SAND":idx = 22;break;default:idx = 0;break;}if (UniStormSystem.Instance != null && idx >= 0 && idx < UniStormSystem.Instance.AllWeatherTypes.Count)UniStormManager.Instance?.ChangeWeatherInstantly(UniStormSystem.Instance.AllWeatherTypes[idx]);
}
其中ChangeWeatherInstantly方法是直接切换,没有过度动画等效果,当然您也可以采用ChangeWeatherWithTransition方法,这个带个过度,如雨转晴中间有个丝滑的过度效果:
源码工程
https://download.csdn.net/download/qq_33789001/90272787
相关文章:

Unity3d 实时天气系统基于UniStorm插件和xx天气API实现(含源码)
前言 实时天气在Unity3d三维数字沙盘中的作用非常重要,它能够增强虚拟环境的真实感和互动性,实时天气数据的应用可以提供更为精准和直观的天气信息支持,如果真实的数据加上特效、声音和模型反馈会提高产品档次,提高真实感。 目前…...

年后找工作需要注意的事项
大家好!我是 [数擎 AI],一位热爱探索新技术的前端开发者,在这里分享前端和 Web3D、AI 技术的干货与实战经验。如果你对技术有热情,欢迎关注我的文章,我们一起成长、进步! 开发领域:前端开发 | A…...

模拟器多开窗口单IP与代理IP关系
模拟器多开窗口同IP背后出现的问题 在游戏世界中,模拟器多开窗口是玩家们提升体验的常见做法。通过在同一设备上开启多个模拟器窗口,玩家可以同时运营多个游戏账号,增加游戏的趣味性和效率。 一旦检测到一个IP地址下登录了过多的账号&#x…...
Android ScrollView嵌套X5WebView大片空白问题
scrollview嵌套后webview的高度不可控。留有大片空白。 注:官方不建议scrollview嵌套webview 最好让webview自身滚动 解决方案: act_news_detail_wv.setWebViewClient(new WebViewClient() {Overridepublic void onPageFinished(WebView webView, Str…...

Java Web开发进阶——WebSocket与实时通信
WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,广泛应用于需要实时数据交换的应用程序中。它能够实现服务器与客户端之间的双向通信,避免了传统 HTTP 请求/响应的延迟。结合 Spring Boot,开发实时通信应用变得更加高效与简便。 1. …...

zerotier搭建虚拟局域网,自建planet
基于该开源项目 自建planet节点,更快速,更安全 本教程依据docker-zerotier-planet 项目文档书写,并以linux(centos 7)和windows作为示例,需要其他系统配置方法,可移步项目文档 一. 前置资源 具有外网ip的服务器 后面…...

SQL面试题1:连续登陆问题
引言 场景介绍: 许多互联网平台为了提高用户的参与度和忠诚度,会推出各种连续登录奖励机制。例如,游戏平台会给连续登录的玩家发放游戏道具、金币等奖励;学习类 APP 会为连续登录学习的用户提供积分,积分可兑换课程或…...

2Spark Core
2Spark Core 1.RDD 详解1) 为什么要有 RDD?2) RDD 是什么?3) RDD 主要属性 2.RDD-API1) RDD 的创建方式2) RDD 的算子分类3) Transformation 转换算子4) Action 动作算子 3. RDD 的持久化/缓存4. RDD 容错机制 Checkpoint5. RDD 依赖关系1) 宽窄依赖2) 为什么要设计宽窄依赖 …...

linux之进程信号(初识信号,信号的产生)
目录 引入一、初识信号(信号预备知识)1.生活中的信号2.Linux中的信号3.信号进程得出的初步结论 二、信号的产生1.通过终端输入产生信号拓展: 硬件中断2.调用系统函数向进程发信号3.硬件异常产生信号4.软件条件产生信号拓展: 核心转储技术总结一下: 引入 一、初识信…...
基于nginx实现正向代理(linux版本)
介绍 在企业开发环境中,局域网内的设备通常需要通过正向代理服务器访问互联网。正向代理服务器充当中介,帮助客户端请求外部资源并返回结果。局域网内也就是俗称的内网,局域网外的互联网就是外网,在一些特殊场景内,例…...

【蓝牙】win11 笔记本电脑连接 hc-06
文章目录 前言步骤 前言 使用电脑通过蓝牙添加串口 步骤 设置 -> 蓝牙和其他设备 点击 显示更多设备 更多蓝牙设置 COM 端口 -> 添加 有可能出现卡顿,等待一会 传出 -> 浏览 点击添加 hc-06,如果没有则点击 再次搜索 确定 添加成…...

小程序组件 —— 31 事件系统 - 事件绑定和事件对象
小程序中绑定事件和网页开发中绑定事件几乎一致,只不过在小程序不能通过 on 的方式绑定事件,也没有 click 等事件,小程序中绑定事件使用 bind 方法,click 事件也需要使用 tap 事件来进行代替,绑定事件的方式有两种&…...

力扣cf补题-1【算法学习day.94】
前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向(例如想要掌握基础用法,该刷哪些题?建议灵神的题单和代码随想录)和记录自己的学习过程,我的解析也不会做的非常详细,只会提供思路和一些关…...

系统学习算法:专题四 前缀和
题目一: 算法原理: 这道题是一维前缀和的模板题,通过这道题我们可以了解什么是前缀和 题意很简单,就是先输入数组个数和查询次数,然后将数组的值放进数组,每次查询给2个数,第一个是起点&#x…...
java 迪米特法则,原理、思想、工作流程、实现细节、稳定性、优缺点、应用场景等
迪米特法则(Law of Demeter,LoD),也被称为“最少知识原则”,是一种指导面向对象设计的原则,旨在减少对象之间的耦合度。以下是对迪米特法则的详细解析。 1. 定义 迪米特法则指出:一个对象应该…...

vue项目引入阿里云svg资源图标
1:生成svg图标 登录阿里云官网 1.1 创建项目组 1.2 从阿里云网站上面获取喜欢的图标加入到已有的项目组 1.3 如果团队有自己的设计师,也可以让设计师上传自己的svg图标到阿里云指定的项目组; 使用的时候,把 资源包下载到本地项…...
存储过程和触发器
目录 1、存储过程 1.1 存储过程的概述 1.2 存储过程的类型 1. 系统存储过程 2. 本地存储过程 3. 临时存储过程 4. 扩展存储过程 1.3 T-SQL创建存储过程 1.4 T-SQL执行存储过程 1.5 T-SQL查看存储过程 1.6 T-SQL修改存储过程 1.7 T-SQL删除存储过程 2、触发器 2.1 …...

《拉依达的嵌入式\驱动面试宝典》—计算机网络篇(二)
《拉依达的嵌入式\驱动面试宝典》—计算机网络篇(二) 你好,我是拉依达。 感谢所有阅读关注我的同学支持,目前博客累计阅读 27w,关注1.5w人。其中博客《最全Linux驱动开发全流程详细解析(持续更新)-CSDN博客》已经是 Linux驱动 相关内容搜索的推荐首位,感谢大家支持。 《…...

【深度学习实战】kaggle 自动驾驶的假场景分类
本次分享我在kaggle中参与竞赛的历程,这个版本是我的第一版,使用的是vgg。欢迎大家进行建议和交流。 概述 判断自动驾驶场景是真是假,训练神经网络或使用任何算法来分类驾驶场景的图像是真实的还是虚假的。 图像采用 RGB 格式并以 JPEG 格式…...

Spring Boot 和微服务:快速入门指南
💖 欢迎来到我的博客! 非常高兴能在这里与您相遇。在这里,您不仅能获得有趣的技术分享,还能感受到轻松愉快的氛围。无论您是编程新手,还是资深开发者,都能在这里找到属于您的知识宝藏,学习和成长…...

wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...

无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...

免费数学几何作图web平台
光锐软件免费数学工具,maths,数学制图,数学作图,几何作图,几何,AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...