Unity3D學習筆記(十八)使用外掛NGUI製作小地圖
阿新 • • 發佈:2019-01-25
原本只是想用Unity自帶的GUI功能實現魔獸世界的小地圖效果,結果折騰了一個晚上。
原來的思路如下:
在做到一半的時候發現GUI Texture只能使用Texture,無法使用Material,這也就意味著不能使用Shader做遮罩的剔除效果。在網上搜索了好久,發現有好多老外也在問相關的問題,但是就是沒有很合適的解決方案。經過再三考慮之後,咬咬牙決定捨棄系統自帶的GUI功能,使用第三方GUI外掛。
其實之前也有了解過相關的外掛,比如NGUI、EZGUI和IGUI之類的,只不過感覺如果太依賴第三方外掛則會導致“知其然而不知其所以然”,所以也一直沒去學習使用。工欲善其事必先利其器,既然已經決定要使用第三方外掛了,那麼選擇一個趁手的當然是首要問題。
通過比較最終選擇了NGUI,主要參考了這篇《為你的Unity3D專案選擇GUI框架 – EZGUI VS NGUI》。NGUI的全稱是Next – Gen UI(次世代介面),它提供了快速建立常用的2D控制元件的功能,如按鈕、文字框、滾動條等,繼承Unity所見即所得的優良傳統,並實現了Draw Call的合併,以優化效能。
在CSDN裡找到了2.03版本的共享, 傳送門在此。下載解壓之後會得到一個NGUI203d.unitypackage的檔案,雙擊就可以像匯入自帶資源包一樣把NGUI匯入到當前專案中。如果檔案關聯失效了,也可以通過主選單的”Assets→Import
Package→Custom Package…“手動匯入。
最終在Unity的工程面板中就可以得到一個NGUI目錄,裡邊包括了所有的資源,還有一些範例場景(在Examples/Scenes下面)。其相關的中文教程也並不少,有很多達人都共享了他們寶貴的經驗,我這裡就不再贅述基礎知識點了,多問問度娘一定會讓你收穫頗豐。
匯入NGUI後會在主選單中新增NGUI功能選項,方便快速呼叫它的功能。首先點選主選單的“NGUI→Create a New UI”建立一個UI根物件。由於地圖這些都是2D的,所以保持預設的設定建立Simple 2D Camera即可。
點選“Create Your UI”完成,在工程面板中就出現了UI Root(2D),其下面的所有UI物件都會按照指定的佈局渲染到螢幕上,重新命名為MiniMapView。Anchor(錨點)是用來定位的,保持預設的Center(居中)。
點選NGUI的“Atlas Maker”來建立一個圖片集,輸入名字MiniMap,選中工程面板中的地圖縮圖,然後點選Create就可以了。
選中Panel,然後再選擇使用NGUI選單的“Create a Widget”在面板下面建立一個精靈。
到這裡準備工作全部做好了:
可以看到NGUI其實只是在一個主相機視野看不到的地方建立需要顯示的GUI,然後用另外一個正交投影相機將觀察到的內容疊加到主相機上但是做小地圖的時候並不希望它直接渲染到螢幕上,而是渲染到一張紋理上,這樣才可以使用材質配合遮罩的Shader實現不規則的效果。所以還是先得在工程面板中建立一個Render Texture,重新命名為MiniMap,並拖放到Camera的Target Texture屬性上。這樣,所有該攝像機可見的物體都會渲染到MiniMap這張Render Texture中了。
注意還必須把攝像機的清除標誌(Clear Flags)改成純色(Solid Color),並把Background換成黑色。這樣可以讓地圖超出的部分顯示為純黑色。
然後輪到Mask Shader出場咯。把度娘全身都搜了個遍,終於在茫茫人海中找到了它。在工程面板裡建立一個Shader,重新命名為TransparentMast,把以下程式碼複製進去:
再在工程面板中建立一個材質,使用這個Shader,並把前面的Render Texture拖到Base(RGB)上,把遮罩紋理拖到Culling Mask上。這樣,最難的問題就解決了。此時只要把這個材質附加到任何支援材質的物件上,都能顯示小地圖了^_^。比如隨便建立一個平面,把材質附加到Mesh Renderer元件的Materials上:
啊,看起來離最終目標還是有點距離……不過已經可以看出圓形以外的紋理都變透明瞭。
接下來的工作就是慢慢把GUI部分搭建起來。
再建立一個UI Root,這次是用來真正顯示GUI了。由於GUI是預設定位在左上角的,因此可以刪掉原來的Anchor。再建立一個Panel,重新命名為HudPanel。這個面板用來做整體縮放,因為介面上不一定只有小地圖,還有之前做的頭像、動作條之類的,如果需要批量縮放,那麼只要調整這個面板的Scale就好了。
在HudPanel下面建立一個錨點Anchor – RightTop,把Side修改為TopRight,讓它對齊到右上角。再在其下面建立一個Panel,叫做MiniMap,然後在下面分別建立地圖邊框(Sprite)、地圖指北標誌(Sprite)、人物指示標誌(Sprite)、地圖紋理(UITexture),調整XY軸座標定位,調整Depth可以更改顯示優先順序,記得要把前面建立的MiniMap材質賦給地圖紋理。我這裡還多建立了一個Label,用來顯示當前地圖位置,但是會遇到一個字型的問題,這個待會再寫。
好了,玩家指標已經定位在地圖的(0,0)點位置,再寫一個指令碼附加到MiniMap上,讓它能夠實時地反映玩家的當前位置和朝向。
看起來還不錯:)
原來的思路如下:
- 根據玩家座標,計算出應顯示的地圖縮圖部分(128×128);
- 用GUI遮罩將非白色的部分剔除(這樣可以實現任意形狀的小地圖);
- 將地圖框疊加到第二步中的紋理上;
-
將玩家指示物放置在地圖中心,並根據當前玩家的Transform.Rotation計算出指示物的旋轉角度;
在做到一半的時候發現GUI Texture只能使用Texture,無法使用Material,這也就意味著不能使用Shader做遮罩的剔除效果。在網上搜索了好久,發現有好多老外也在問相關的問題,但是就是沒有很合適的解決方案。經過再三考慮之後,咬咬牙決定捨棄系統自帶的GUI功能,使用第三方GUI外掛。
其實之前也有了解過相關的外掛,比如NGUI、EZGUI和IGUI之類的,只不過感覺如果太依賴第三方外掛則會導致“知其然而不知其所以然”,所以也一直沒去學習使用。工欲善其事必先利其器,既然已經決定要使用第三方外掛了,那麼選擇一個趁手的當然是首要問題。
通過比較最終選擇了NGUI,主要參考了這篇《為你的Unity3D專案選擇GUI框架 – EZGUI VS NGUI》。NGUI的全稱是Next – Gen UI(次世代介面),它提供了快速建立常用的2D控制元件的功能,如按鈕、文字框、滾動條等,繼承Unity所見即所得的優良傳統,並實現了Draw Call的合併,以優化效能。
在CSDN裡找到了2.03版本的共享,
最終在Unity的工程面板中就可以得到一個NGUI目錄,裡邊包括了所有的資源,還有一些範例場景(在Examples/Scenes下面)。其相關的中文教程也並不少,有很多達人都共享了他們寶貴的經驗,我這裡就不再贅述基礎知識點了,多問問度娘一定會讓你收穫頗豐。
匯入NGUI後會在主選單中新增NGUI功能選項,方便快速呼叫它的功能。首先點選主選單的“NGUI→Create a New UI”建立一個UI根物件。由於地圖這些都是2D的,所以保持預設的設定建立Simple 2D Camera即可。
點選“Create Your UI”完成,在工程面板中就出現了UI Root(2D),其下面的所有UI物件都會按照指定的佈局渲染到螢幕上,重新命名為MiniMapView。Anchor(錨點)是用來定位的,保持預設的Center(居中)。
點選NGUI的“Atlas Maker”來建立一個圖片集,輸入名字MiniMap,選中工程面板中的地圖縮圖,然後點選Create就可以了。
選中Panel,然後再選擇使用NGUI選單的“Create a Widget”在面板下面建立一個精靈。
到這裡準備工作全部做好了:
可以看到NGUI其實只是在一個主相機視野看不到的地方建立需要顯示的GUI,然後用另外一個正交投影相機將觀察到的內容疊加到主相機上但是做小地圖的時候並不希望它直接渲染到螢幕上,而是渲染到一張紋理上,這樣才可以使用材質配合遮罩的Shader實現不規則的效果。所以還是先得在工程面板中建立一個Render Texture,重新命名為MiniMap,並拖放到Camera的Target Texture屬性上。這樣,所有該攝像機可見的物體都會渲染到MiniMap這張Render Texture中了。
注意還必須把攝像機的清除標誌(Clear Flags)改成純色(Solid Color),並把Background換成黑色。這樣可以讓地圖超出的部分顯示為純黑色。
然後輪到Mask Shader出場咯。把度娘全身都搜了個遍,終於在茫茫人海中找到了它。在工程面板裡建立一個Shader,重新命名為TransparentMast,把以下程式碼複製進去:
-
Shader "Transparent/Mask"
-
{
-
Properties
-
{
-
_MainTex ("Base (RGB)", 2D) = "white" {}
-
_Mask ("Culling Mask", 2D) = "white" {}
-
_Cutoff ("Alpha cutoff", Range (0,1)) = 0
-
}
-
SubShader
-
{
-
Tags {"Queue"="Transparent"}
-
Lighting Off
-
ZWrite Off
-
Blend SrcAlpha OneMinusSrcAlpha
-
AlphaTest GEqual [_Cutoff]
-
Pass
-
{
-
SetTexture [_Mask] {combine texture}
-
SetTexture [_MainTex] {combine texture, previous}
-
}
-
}
- }
再在工程面板中建立一個材質,使用這個Shader,並把前面的Render Texture拖到Base(RGB)上,把遮罩紋理拖到Culling Mask上。這樣,最難的問題就解決了。此時只要把這個材質附加到任何支援材質的物件上,都能顯示小地圖了^_^。比如隨便建立一個平面,把材質附加到Mesh Renderer元件的Materials上:
啊,看起來離最終目標還是有點距離……不過已經可以看出圓形以外的紋理都變透明瞭。
接下來的工作就是慢慢把GUI部分搭建起來。
再建立一個UI Root,這次是用來真正顯示GUI了。由於GUI是預設定位在左上角的,因此可以刪掉原來的Anchor。再建立一個Panel,重新命名為HudPanel。這個面板用來做整體縮放,因為介面上不一定只有小地圖,還有之前做的頭像、動作條之類的,如果需要批量縮放,那麼只要調整這個面板的Scale就好了。
在HudPanel下面建立一個錨點Anchor – RightTop,把Side修改為TopRight,讓它對齊到右上角。再在其下面建立一個Panel,叫做MiniMap,然後在下面分別建立地圖邊框(Sprite)、地圖指北標誌(Sprite)、人物指示標誌(Sprite)、地圖紋理(UITexture),調整XY軸座標定位,調整Depth可以更改顯示優先順序,記得要把前面建立的MiniMap材質賦給地圖紋理。我這裡還多建立了一個Label,用來顯示當前地圖位置,但是會遇到一個字型的問題,這個待會再寫。
好了,玩家指標已經定位在地圖的(0,0)點位置,再寫一個指令碼附加到MiniMap上,讓它能夠實時地反映玩家的當前位置和朝向。
-
void Update()
-
{
-
const float miniMapScaleRatio = 800 / 2000f;
-
MiniMapArrow.rotation = Quaternion.Euler(0, 0, -mPlayerTransform.rotation.eulerAngles.y);
-
MiniMapPanel.localPosition = new Vector3()
-
{
-
x = -mPlayerTransform.position.x * miniMapScaleRatio,
-
y = -mPlayerTransform.position.z * miniMapScaleRatio,
-
z = 0,
-
};
- }
看起來還不錯:)