开发实战
# 开发实战
通过场景开发、三维设备开发、UI控件开发三个案例,从拿到二次开发包开始,一直到在3D可视化平台看到实际效果,完整的演示整个流程。
二次开发包可以从3D开发开源仓库 (opens new window)中获取,三个案例均使用此开发包,以下不再赘述。
# 场景开发
开发步骤
创建项目。首先打开Unity Hub ,点击打开按钮旁边的倒三角,选择从磁盘添加项目。

点击到开发包路径,选择iotcenter-3d-development文件夹,点击添加项目.

此时项目列表会出现添加后的文件夹名称,双击打开即可。打开后界面如下,编辑器工具也会自动打开
提示
若编辑器工具没有自动打开,参考编辑器工具部分内容打开编辑器工具。如果布局和案例不一样,是因为Unity布局可以自定义,可随意修改。

创建新场景。打开项目后,打开编辑器工具,然后在侧边栏点击新建场景按钮。
提示
本教程使用编辑器工具创建场景,工具会将一些必要的、重复的操作自动完成,比如创建设备预制体等等。

根据弹窗提示选择文件夹并填写文件名称然后保存即可创建新场景。

注意
场景文件名称必须全部小写
创建完成后场景的默认结构如下:

提示
Main Camera物体用于在Game视图调试效果,在Bulid更新包时需要隐藏掉。增加模型。在场景中添加一个
Cube模型
提示
Bulid更新包时,请注意场景是否保存,如果没有保存场景,Bulid后不会显示没保存的数据。构建AB包。
首先需要设置
IoT 3D平台的路径,在编辑器工具窗口选择AssetBundles点击Browse选择路径。
点击
Open Folder可以打开当前配置的路径。
点击
Bulid按钮等待构建完成。
构建进度条消失后点击
Run IoTCenter3D按钮打开3D平台。
平台预览。输入服务器地址、用户名、密码,登录平台。

登录成功后进入编辑模式。

创建场景。
提示
- 首先打开场景编辑面板
- 选中根节点
Scene - 点击添加场景

为场景设置名称.

点击三维场景可以看到刚才创建的场景,鼠标选中点击选择即可加载场景。

创建的cube正常显示在场景中.

# 三维设备开发
开发步骤
创建项目。参考场景开发部分的内容创建项目即可。
创建
Cube设备。提示
本教程使用编辑器工具创建场景,工具会将一些必要的、重复的操作自动完成,比如创建设备预制体等等。
打开编辑器工具后,创建设备页面默认显示,填写基本脚本名称、设备名称等参数后点击创建即可(设备模型和设备图表可以为空,也可以为其选择物体和图标)。

等待一会,场景中已经添加了刚才创建的设备预制体,点击
Open进入编辑。
添加
Cube模型,保存预制体。
构建AB包。参考场景开发部分的内容构建AB包即可。
平台预览。登录3D平台,并进入编辑模式后点击资源库,下拉滚动条即可看到创建的设备

# UI控件开发
制作网络图片UI控件为例介绍UI控件的开发步骤。
提示
本次案例代码可以在二次开发包中查看,路径如下:
- UI_NetworkImage.cs:
\iotcenter-3d-development\Assets\SceneModule\TianjinPortScenes\UIControl\Scripts - UI_NetworkImage:
\iotcenter-3d-development\Assets\SceneModule\TianjinPortScenes\UIControl\Prefabs
开发步骤
创建项目。参考场景开发部分的内容创建项目即可。
创建控件
提示
本教程使用编辑器工具创建场景,工具会将一些必要的、重复的操作自动完成,比如创建设备预制体等等。
由于本案例是显示一个网络图片所以需要创建UI控件。点击编辑器工具控件类型下拉框,选择UI控件。

创建控件页面会自动弹出,设置好参数后,也可以查看代码的实时预览,确定无误后点击创建按钮,等待自动完成创建基本代码和预制体。

自动创建完成后,场景中会多出
Canvas物体,展开后可以看到UI控件默认预制体
制作界面。
在编辑器工具中,选择控件类型为UI控件,在控件列表中点击创建的UI在控件详情页面中点击
预览控件,会打开预制体专属场景。
打开场景后,点击
2D按钮 只看平面视图,更好的制作UI界面。
选中控件,首先设置
UI控件在IOT 3D平台时显示的名称
由于自动创建的UI 控件默认是一个
Image,但是本案例选择不用Image,所以删除Image组件。
本案例使用
RawImage,在UI_NetworkImage物体下新建一个RawImage子物体。
设置
RawImage锚点,这样可以在IOT 3D平台调整图片大小。
编写脚本。
选中预制体根物体,双击脚本组件下的引用可以在
IDE打开
代码模板:
using UnityEngine.UI; public class UI_NetworkImage : UIControl { /// <summary> /// 用于公开给用户配置的属性 /// </summary> #region 属性 [SerializeField] private string m_tips; public string Tips { get { return m_tips; } set { m_tips = value; } } #endregion /// <summary> /// 定义平台显示UI控件时在哪个分类 /// </summary> public override UIResEnum uIResEnum => UIResEnum.Other; /// <summary> /// 获取配置的属性后调用 /// </summary> public override void OnSerialized() { } private void Awake() { } /// <summary> /// UI在平台隐藏时调用 /// </summary> public override void OnClose() { base.OnClose(); } /// <summary> /// UI在平台显示时调用 /// </summary> public override void OnOpen() { base.OnOpen(); } /// <summary> /// 用于获取子物体组件的方法 /// </summary> /// <typeparam name="T">组件类型</typeparam> /// <param name="name">物体在预制体中的名称</param> /// <returns></returns> T GetGame<T>(string name) { return transform.Find(name).GetComponent<T>(); } }为了获取RawImage,定义RawImage类型的字段,需要引用UnityEngine.UI。
using UnityEngine.UI;字段定义如下:
/// <summary> /// 定义一个 RawImage /// </summary> RawImage rawImage;在
Awake方法中获取到RawImage。private void Awake() { //获取到 RawImage rawImage = GetGame<RawImage>("RawImage"); }删除默认创建的属性,创建一个公开属性
URL,用户可以在IOT 3D平台进行配置,让控件更加通用,同时也可以赋一个默认值,让控件默认就能加载出一张网络图片。/// <summary> /// 用于公开给用户配置的属性 /// </summary> #region 属性 [SerializeField] private string m_url = "https://s3.bmp.ovh/imgs/2022/07/15/1abf154a41a46201.jpg"; public string Url { get { return m_url; } set { m_url = value; Debug.Log(value); } } #endregion使用协程获取网络图片。
添加如下引用:
using System.Collections; using UnityEngine.Networking;获取网络图片方法如下所示:
/// <summary> /// 获取图片 /// </summary> /// <returns></returns> IEnumerator LoadImage() { //使用Unity提供的API获取网络图片 UnityWebRequest www = UnityWebRequestTexture.GetTexture(Url); //等待图片返回 yield return www.SendWebRequest(); //判断是否获取图片失败 if (www.result == UnityWebRequest.Result.ConnectionError) Debug.Log(www.error); else { //获取图片成功后,如果有,先删除之后的图片防止内存泄漏 if (rawImage.texture) DestroyImmediate(rawImage.texture); //设置图片到 RawImage组件 rawImage.texture = DownloadHandlerTexture.GetContent(www); } //释放UnityWebRequest www.Dispose(); }在每次显示组件时获取一次图片。
/// <summary> /// UI在平台显示时调用 /// </summary> public override void OnOpen() { base.OnOpen(); //打开时获取一次图片 StartCoroutine(LoadImage()); }完整代码如下:
using System.Collections; using UnityEngine; using UnityEngine.Networking; using UnityEngine.UI; public class UI_NetworkImage : UIControl { /// <summary> /// 用于公开给用户配置的属性 /// </summary> #region 属性 [SerializeField] private string m_url = "https://s3.bmp.ovh/imgs/2022/07/15/1abf154a41a46201.jpg"; public string Url { get { return m_url; } set { m_url = value; Debug.Log(value); } } #endregion /// <summary> /// 定义一个 RawImage /// </summary> RawImage rawImage; /// <summary> /// 定义平台显示UI控件时在哪个分类 /// </summary> public override UIResEnum uIResEnum => UIResEnum.Other; /// <summary> /// 获取配置的属性后调用 /// </summary> public override void OnSerialized() { } private void Awake() { //获取到 RawImage rawImage = GetGame<RawImage>("RawImage"); } /// <summary> /// UI在平台隐藏时调用 /// </summary> public override void OnClose() { base.OnClose(); } /// <summary> /// UI在平台显示时调用 /// </summary> public override void OnOpen() { base.OnOpen(); //打开时获取一次图片 StartCoroutine(LoadImage()); } /// <summary> /// 获取图片 /// </summary> /// <returns></returns> IEnumerator LoadImage() { //使用Unity提供的API获取网络图片 UnityWebRequest www = UnityWebRequestTexture.GetTexture(Url); //等待图片返回 yield return www.SendWebRequest(); //判断是否获取图片失败 if (www.result == UnityWebRequest.Result.ConnectionError) Debug.Log(www.error); else { //获取图片成功后,如果有,先删除之后的图片防止内存泄漏 if (rawImage.texture) DestroyImmediate(rawImage.texture); //设置图片到 RawImage组件 rawImage.texture = DownloadHandlerTexture.GetContent(www); } //释放UnityWebRequest www.Dispose(); } /// <summary> /// 描述文件调用 /// </summary> public void UpdateImg() { Debug.Log("UpdateImg"); StartCoroutine(LoadImage()); } /// <summary> /// 用于获取子物体组件的方法 /// </summary> /// <typeparam name="T">组件类型</typeparam> /// <param name="name">物体在预制体中的名称</param> /// <returns></returns> T GetGame<T>(string name) { return transform.Find(name).GetComponent<T>(); } }
构建AB包。参考场景开发部分的内容构建AB包即可。
平台预览。
登录3D可视化平台并进入编辑模式后,选中
UI资源库,选择其他分类,因为网络图片控件代码中将分类设置成了Other。
控件名称也和设置的一样显示为网络图片。

将其拖动到场景中,会加载出默认图片,并且公开属性
URL也可以配置
# 进阶
在平台预览时发现修改公开属性URL的网址,只能保存后重启三维才能更新。进阶要实现重新填写网址后能实时更新获取图片。
开发步骤
创建描述文件。首先找到
UI_NetworkImage脚本,在其目录下创建文件夹ComponentDescriptors。在创建的文件夹下新建脚本
NetworkImageComponentDescriptor.cs(类名可以修改)。编写脚本。
默认脚本。
using System.Reflection; using UnityEngine; public class NetworkImageComponentDescriptor : MonoBehaviour { //Start is called before the first frame update void Start() { } //Update is called once per frame void Update() { } }填加特性
[BuiltInDescriptor],继承ComponentDescriptorBase类,并且重写GetProperties方法。using IoT3D.RunTimeEditor; /// <summary> /// UI_NetworkImage 描述文件 /// </summary> [BuiltInDescriptor] public class NetworkImageComponentDescriptor : ComponentDescriptorBase<UI_NetworkImage> { public override PropertyDescriptor[] GetProperties(ComponentEditor editor, object converter) { throw new System.NotImplementedException(); } }编写获取
UI_NetworkImage的公开属性URL,并且设置回调方法等。同时UI_NetworkImage也可以增加一个公开方法用于刷新数据。提示
这里编写了两种回调,采用的是
endEditCallback回调,也就是输入框输入完成后才回调using IoT3D.RunTimeEditor; using IoT3D.Utils; using System.Collections.Generic; using System.Reflection; using UnityEngine; /// <summary> /// UI_NetworkImage 描述文件 /// </summary> [BuiltInDescriptor] public class NetworkImageComponentDescriptor : ComponentDescriptorBase<UI_NetworkImage> { public override PropertyDescriptor[] GetProperties(ComponentEditor editor, object converter) { this.editor = editor; //设置值更改回调 PropertyEditorCallback valueChanged; valueChanged = OnValueChanged; //设置值结束回调 PropertyEditorCallback valueEnd; valueEnd = OnValueEnd; //获取选中的第一个控件 dev_Image = editor.Components[0] as UI_NetworkImage; List<PropertyDescriptor> descriptors = new List<PropertyDescriptor>(); //获取属性 MemberInfo urlInfo = Strong.PropertyInfo((UI_NetworkImage x) => x.Url, "Url"); //设置显示名称、回调 descriptors.Add(new PropertyDescriptor("链接", editor.Components, urlInfo, urlInfo, valueChanged, valueEnd)); return descriptors.ToArray(); } /// <summary> /// 值更改 /// </summary> public virtual void OnValueChanged() { Debug.LogError("OnValueChanged"); } /// <summary> /// 值结束 /// </summary> public virtual void OnValueEnd() { dev_Image.UpdateImg(); } }
- `UI_NetworkImage.cs`类中增加`UpdateImg`方法用于描述文件接收到值更改后调用。 ```csharp /// <summary> /// 描述文件调用 /// </summary> public void UpdateImg() { Debug.Log("UpdateImg"); StartCoroutine(LoadImage()); } ```平台预览
由于只是修改了代码,可以直接点击
OnlyCopyScrpts按钮将代码拷贝到平台,然后点击RunIoTCenter3D启动平台。
此时修改网址后,图片实时修改成功。
