开发实战
# 开发实战
通过场景开发、三维设备开发、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
启动平台。此时修改网址后,图片实时修改成功。