Unity3D Demo項目開發記錄


  前言

  經過一段時間的學習與實際開發,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、碼雲:

  GitHub:https://github.com/huanzi-qch/unity-demo

  碼雲:https://gitee.com/huanzi-qch/unity-demo


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM