前言
經過一段時間的學習與實際開發,unity3D也勉強算是強行入門了,正所謂好記性不如爛筆頭,更何況本人並非專業從事unity3D開發,會一點C#但也並不熟悉,為了避免后期遺忘,因此特意整理了一個Demo項目,特此記錄
本項目是一個簡單的Unity學習項目,封裝了一下簡單、通用功能組件,適用於數據可視化展示
項目特色
1、封裝了簡單Camera鏡頭操作、鏡頭巡航腳步
2、封裝單擊、雙擊事件同時綁定腳本(unity3D 游戲物體同時綁定單擊、雙擊事件)
3、封裝永遠面向屏幕、跟隨鏡頭旋轉縮放,縮放大小不變的Billboard公告牌腳本(unity3D 自定義公告牌 )
4、利用LineRenderer,封裝自定義流動線路腳本
5、封裝自定義彈窗,帶遮陰層,可拖動
6、項目用到BestHTTP插件,網傳最好用的http插件
7、項目用到XCharts插件,豐富圖表展示足夠滿足需求
8、項目用到DoTween插件,在代碼中可輕松實現各種動畫效果
項目結構
整體是這樣:大目錄下進行分組,對應的資源分組存放
場景結構
約定,除了背景、攝鏡頭、燈光外,所有的3D對象全都放在ObjectRoot下面,所有的UI全都放在UIRoot下面,場景主腳本Main.cs掛在ObjectRoot下面,封裝的自定義彈窗腳本Dialog.cs掛在UIRoot下面
運行預覽
效果先睹為快,具體介紹在下方,按功能點進行詳情介紹
功能詳解
背景圖
需要單獨創建一個攝像頭,並只看背景圖片,這樣才能跟主攝像頭相互不影響
背景圖片是從網上找的素材,簡單的PS了一下,圖片風格,黑中帶藍、藍中帶紫、紫色中透着白光,四周偏暗,中間偏亮,也就網傳“五彩斑斕的黑”能夠與之一拼,更能凸顯3D主體對象
鏡頭操作
包括鏡頭縮放、鼠標左鍵進行上下左右旋轉,同時可定點巡航、以及指定路線巡航
定點巡航,給定一個坐標點,鏡頭將會圍繞目標點巡航360度
定線巡航,給定多個坐標點,鏡頭就會依次推進到指定位置,當然了,路線的選擇決定了巡航的最終效果,像我這里的坐標點就選得不行,3D對象都跑出鏡頭外了...
單雙擊事件綁定
unity3D 游戲物體同時綁定單擊、雙擊事件,具體實現看之前的博客:unity3D 游戲物體同時綁定單擊、雙擊事件
自定義公告牌
永遠面向屏幕、跟隨鏡頭旋轉縮放,縮放大小不變的Billboard公告牌,具體實現看之前的博客:unity3D 自定義公告牌
流動線路
利用LineRenderer進行畫線,材質球設置好流動的光點背景圖,封裝好腳本,在update中修改材質球的mainTextureOffset值,以一定的速度進行增加或減小,從而達到光點流動的效果,同時利用貝塞爾曲線(參考博客:https://www.cnblogs.com/msxh/p/6270468.html)實現一定的弧度彎曲效果
自定義彈窗
自定義彈窗,帶遮陰層,彈出彈窗時鼠標無法操作對象(3D、按鈕等),同時左鍵長按標題欄可拖動彈窗,封裝了四個簡單彈窗:alert警告框,affirm確認框,scrollBox滾動框,msg提示框
可輸出普通文本,也可以操作追加3D對象(如下面的模擬監控功能)
2020-07-28更新
我們之前是定義public的預制體變量,在編輯器進行拖拉賦值,預制體是放在Prefabs文件夾
為了簡化這步操作,我決定改成動態加載預制體,首先將預制體放到Resources文件夾下面,然后再代碼中進行動態讀取
public void Start() { loadPrefabs(); } /// <summary> /// 動態加載預制體 /// </summary> private void loadPrefabs() { scrollBoxPrefab = (GameObject)Resources.Load("Dialog/ScrollBox"); affirmPrefab = (GameObject)Resources.Load("Dialog/Affirm"); alertPrefab = (GameObject)Resources.Load("Dialog/Alert"); msgPrefab = (GameObject)Resources.Load("Dialog/Msg"); }
XCharts圖表
一款基於`UGUI`的功能強大、易用、參數可配置的數據可視化圖表插件。支持折線圖、柱狀圖、餅圖、雷達圖、散點圖、熱力圖等常見圖表。
XCharts主頁:https://github.com/monitor1394/unity-ugui-XCharts
插件自帶一個demo場景,各種圖表都有例子
拿過來改一改就能用
BestHTTP請求
BestHTTP在網上一搜,好多都說是最好用、最強大的HTTP插件,有各種強大的騷操作,具體的自行百度了解,因為我們現在用不上,簡單的http get、post請求,以及json轉C#對象就夠我們用了
插件同樣自帶demo場景,里面有各種例子
http請求,發送get、post(PS:如果是打包成WebGL,由於瀏覽器的同源策略,會存在跨域問題,這一點需要注意),比如我們在程序一運行就發起get請求獲取配置文件信息,並在UI面板中設置
Panel面板
一個帶背景圖的簡單基礎預制體,可作為其他UI面板的基礎
DoTween動畫
強大的動畫插件,更多介紹查看官網:http://dotween.demigiant.com/documentation.php
項目中常用的就UI面板的進場、離場動畫、以及3D對象的動畫,比如我們這里的標題、按鈕組、左右UI面板都有一個進場動畫
模擬監控
使用自定義alert彈窗彈出,目前是直接播放mp4格式視頻,做這個組件,主要是為后續接入視頻監控做儲備
注:unity自帶的視頻播放組件存在一些問題,有時候會導致程序直接崩掉,我就經常碰到,比如在代碼中修改視頻url,經常卡死程序自動退出...
場景切換
2020-08-21更新:新增場景切換過渡動畫效果,像舞台開幕、閉幕一樣
WebGL打包
Edit -> Project Serrings -> Quality 進行WebGL打包參數設置
File -> Build Settings,添加需要打包的場景,選擇WebGL,Build,選擇文件夾打包,接下來就是等待了,時間看電腦配置,配置越好打包速度越快
后記
開發中,有些功能我們沒必要重復造輪子,網上可以找到很多插件,各式各樣的功能都有,比如這個網站:http://www.6m5m.com/index.php
不過作者錢包五行缺錢,平時學習時只能下載0金幣0積分的資源....,但如果是碰到項目能用的上,又是比較必要的插件,可以讓經理或者公司去充值購買
Unity 3D Demo項目暫時記錄到這,后續再進行補充
注意:unity中使用默認的字體,打包成WebGL后字體會丟失,導致文字缺失
補充更新
2020-07-31更新
1、新增“3D物體轉2D屏幕坐標”腳本;
2、重寫原生按鈕腳本,擴展鼠標懸浮等事件;
2020-09-01更新
如何讀取、寫入txt文件? 注意:打成WebGL后,Application.streamingAssetsPath獲取到的是http鏈接,File讀取會報錯
//新建test.txt空白文件 string path = Application.streamingAssetsPath + "/test.txt"; //寫入 File.WriteAllText (path, "{\"name\":\"huanzi\"}", Encoding.UTF8); //讀取 File.ReadAllText(path); //{"name":"huanzi"}
如何序列化、反序列化List、Dictionary集合對象?參考下面的博客,親測可用
Unity中JsonUtility對List和Dictionary的序列化:https://blog.csdn.net/truck_truck/article/details/78292390
unity調用js
打成WebGL后,我們有時想操作js應該如何做?這里記錄一下實現過程
Plugins目錄下面創建JsLib新目錄,新增HuanZiJsLib.jslib文件,內容如下:
在C#中調用
//引入、指定js方法 [DllImport("__Internal")] private static extern void Test(string text); //引入、指定js方法 [DllImport("__Internal")] private static extern void GoToView(string url); //調用 Test("C#調用JS"); GoToView("http://xxxxxxx");
打成WebGL后才有效果,其他運行方式無效
2020-11-27更新
1、封裝定點焦聚,開發中我們經常會用到定點焦聚功能,傳入一個坐標點,把鏡頭焦聚過去,同時設置鏡頭目標點
在CameraMove.cs中封裝定點焦聚方法
/// <summary> /// 封裝鏡頭聚焦,傳入一個坐標,鏡頭聚焦過去 /// </summary> /// <param name="point">聚焦坐標</param> /// <param name="duration">焦聚動畫時長</param> /// <param name="distance">鏡頭推薦距離</param> /// <param name="callback">聚焦結束回調</param> public void CamerafocusByPoint(Vector3 point,float duration,float distance,Action callback) { canMove = false; canRotation = false; canZoom = false; distance = Vector3.Distance(this.transform.position, point) - distance; //獲取攝像頭移動的目標坐標 moveTargetPoint = GetBetweenPointByDist(transform.position, point, distance); //把攝像朝向目標點 this.transform.DOLookAt(point, duration).OnComplete(() => { currentAngleForX = this.transform.eulerAngles.x; if (callback != null) { callback.Invoke(); } }); //重設旋轉軸心點 rotaAxis = new Vector3(point.x, 0, point.z); float dist = Vector3.Distance(this.transform.position, moveTargetPoint); Vector3 move = Vector3.Lerp(this.transform.position, moveTargetPoint, Time.deltaTime * 5); this.transform.position = dist > 0.01f ? move : moveTargetPoint; if (Vector3.Distance(this.transform.position, moveTargetPoint) == 0) { moveTargetPoint = Vector3.zero; canMove = true; canRotation = true; canZoom = true; } }
調用
//按鈕9,定點焦聚 buttonGroup.Find("Button9").GetComponent<Button>().onClick.AddListener(() => { Camera.main.GetComponent<CameraMove>().CamerafocusByPoint(GameObject.Find("Rack").transform.position,2F,5F,null); });
效果
2、開發中,我們可能會碰到這種需求:使用鼠標操作的UI對象(例如長滾動列表等),僅操作UI對象,不操作3D世界,這時應該怎么做呢?
首先,我們要獲取到鼠標移動到UI上時,射線穿過的所有UI對象,如何判斷哪個UI需要僅操作UI對象不操作3D世界呢?可在對應的UI對象綁定上一個自定義腳本,判斷射線穿過的所有UI對象中,有綁定自定義腳本的UI時,停用鼠標對3D世界的操作即可;
自定義腳本
/// <summary> /// 綁定該腳本在UI對象,鼠標懸浮在當前對象時停用鼠標操作鏡頭 /// </summary> public class CameraEnableByMouseHovering : MonoBehaviour { }
獲取鼠標射線穿過的UI對象
public class IsPointerOverUI { //射線上所有UI對象 public List<RaycastResult> results; /// <summary> /// 判斷鼠標是否放在UI上,作用等同於:EventSystem.current.IsPointerOverGameObject() /// </summary> /// <returns></returns> public bool IsPointerOverUIObject() { PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current); eventDataCurrentPosition.position = new Vector2(Input.mousePosition.x, Input.mousePosition.y); results = new List<RaycastResult>(); EventSystem.current.RaycastAll(eventDataCurrentPosition, results); return results.Count > 0; } }
在CameraMove中進行判斷
/// <summary> /// 是否停用鼠標操作鏡頭 /// </summary> private bool IsEnable() { //鼠標是否放在UI上 IsPointerOverUI ip = new IsPointerOverUI (); if (ip.IsPointerOverUIObject()) { for (var i = 0; i < ip.results.Count; i++) { //該UI對象是否有綁定我們在CameraEnableByMouseHovering腳本 CameraEnableByMouseHovering cameraEnableByMouseHovering = ip.results[i].gameObject.GetComponent<CameraEnableByMouseHovering>(); if (cameraEnableByMouseHovering != null) { return true; } } } return false; }
當鼠標進行,滾輪縮放、左鍵移動鏡頭等操作時,調用IsEnable進行判斷
/// <summary> /// 鼠標左鍵雙擊移動攝像頭到事件坐標 /// </summary> private void Move() { if (IsEnable()) { return; } //省略其他代碼 }
效果
2020-11-30更新
unity自帶在JSON庫太弱了,復雜在情況下不能滿足我們在要求,這時候就要換一個JSON庫
window -> Asset Store,搜索JSON .NET For Unity,下載、安裝
序列化
反序列化
代碼開源
代碼已經開源、托管到我的GitHub、碼雲: