Unity - 使用內建ToggleGroup來製作簡易面板切換(Using build-in toggle group to create simple panel switch) Ver.2

  前一個版本我用了兩個ToggleGroup來做,事實上是用一個ToggleGroup就可以簡單做到面板切換了,不過我也忘記當初是為了什麼設計所以使用了兩個ToggleGroup,不過也沒差,如果有使用兩個的需求也是可以做的。


Unity - 使用內建ToggleGroup來製作簡易面板切換(Using build-in toggle group to create simple panel switch)

  UI面板切換,算是一個會需要用到的功能,基本上就是製作了幾個面板資料,按了按鈕切換到對應的面板顯示,此時要把其他不相關的面板暫時關閉。


  舉例來說,我製作了三個面板,對應了三個按鈕Tab1、Tab2、Tab3,面板當中各自有各自的資料,按下Tab2的時候要把Tab3的物件關閉,不然會因為前後順序的關係會擋住Tab2的面板。

  這邊的重點就是不管我按了哪一個Tab,都要把前一個開啟的Panel關閉,然後打開我按下Tab所屬的Panel,這個功能剛好可以使用Unity內建的UI物件ToggleGroup來做到。

  PS:這邊用兩個ToggleGroup單純是因為遇到有人分兩個部分在做,所以這邊也就說明使用兩個ToggleGroup的方式,不然的話只要上面那個Tab的ToggleGroup就夠了,都在Tab的Toggle OnValueChanged裡面去把Panel跟其他物件SetActive,也比較省事。


Unity - PuzzleGame 8 (類金庫輪盤鎖)

  保險箱轉盤遊戲,基本上就是密碼解鎖而已,依據提示或是任何遊戲系統給的資訊,來左右旋轉轉盤到特定刻度,直到一串組合是符合打開的順序,就解決問題了。

  通常在旋轉的階段是非常簡單的,只要照著順序轉就好,因此遊戲通常會把密碼順序的提示給放在不同的地方,玩家需要拼湊出密碼的組合之後才能解開這個鎖,而尋找提示的過程又可以加入其他不同類型的謎題來增加阻礙。




  製作使用的Unity版本為5.4.1 f1。

Unity - PuzzleGame 7 (連動開關)

  連動開關,當某個按鈕按下去的時候同時會有數個其他的開關也會做切換,這邊做的是一種也容易看到的,當移動石柱(我這邊用石柱的圖片,也可以是其他東西)的時候,會有其他幾個石柱也會跟著移動,方向不一定相同,並且移動的單位也不同。

  場景中可能會有一條基準線或是目標線,遊戲的目的就是要讓所有的物件都到達目標線,另外有一種是並非所有物件都用同一條目標線,而是每個物件需求的高度都不同。



  製作使用的Unity版本為5.4.1 f1。

Unity - PuzzleGame 6 (圓餅轉盤)

  旋轉圓餅圖遊戲?!其實也就是左右旋轉時的步數或角度不同,轉過去後會切換那個區塊的開關,遊戲的目的就是要把所有圓餅的區塊都打開。

  類似的規則很多,左右轉的差異也不一定是2或3,乍看之下會容易被圓餅搞混,事實上是可以把它想像一條直線有8個格子,前進跟後退的步數不同而已。



  製作使用的Unity版本為5.4.1 f1。

Unity - VR - 簡易畫面最上層UI顯示

  其實跟一般遊戲的顯示UI差不多,就只是在VR裡面呈現而已,所要呈現的目標就是當按下Menu按鈕或是遊戲系統跳出提示等等,這個時候會跳出一個UI介面面板,這個面板會在最上層顯示,不會被場景中的任何物件擋住。

  這邊用個還算簡單的方法來達到這麼目標,也就是用兩個Camera來照各自的物件即可,遊戲的Camera照場景Culling Mask排除UI物件,而UI Camera則只有照UI物件,排除其他物件。

  

Unity - 2D簡易敵人位置指標(使用UGUI)

  簡單製作一個標示敵人位置的功能,同時使用UGUI讓指標顯示在UI面板上,當然還有許多可以增強的功能,不過這邊就單純製作標示位置而已。


  製作的Component裡有使用(Unity - 物件世界座標(World position) <-> UI座標(UGUI position)的互換 )所製作的方法。



  實作測試,箭頭標示敵人方位 (WebGL build) (滑鼠點擊箭頭可讓鏡頭移動到敵人位置)






  首先製作一個箭頭圖片,這邊就用一張三角形來代替,圖片匯入Unity之後打開Sprite Editor視窗,先來編輯Pivot point的位置,把它移動到尖端的地方。


  上圖的Pivot point已經設定到尖端點了,可以看到位置是(0.5, 0.925),數值記下來,之後還會用到。





  接著建立一個UI canvas物件,並且再建立一個Image物件,把剛剛那個箭頭的Sprite圖設定到這Image物件上,調整一個適當的長寬,這邊我Height拉長了一點讓它在畫面中看起來比較像箭頭。


  接著設定這個箭頭的Pivot點,把剛剛Sprite Editor裡面Pivot的數值設定上去,這樣到時候旋轉這個箭頭就會以這個點為中心旋轉。





  接著就來製作一個簡單的Component,來讓這個箭頭動作。
  大致上流程就是:怪物座標- > UI座標 -> 限制UI座標在畫面中 -> 設定箭頭圖片到這個座標 -> 調整箭頭圖片角度。

  參考Class,座標轉換UIPosition.WorldToUI()的方法來自(Unity - 物件世界座標(World position) <-> UI座標(UGUI position)的互換 )。
public class EnemyArrow : MonoBehaviour
{
    public RectTransform uiRect; //UI canvas的RectTransform
    public UnityEngine.UI.Image arrow; //箭頭圖
    
    public MeshRenderer enemy; //我這邊是用顆隨意亂跑的球Mesh,直接抓上來設定

    //這邊就暫時放在Update()裡面讓它每個frame都更新,視自己需求修改
    void Update()
    {
        UpdateArrow(uiRect, enemy.transform.position, arrow);

        //隨意做的一個切換箭頭的顯示,讓敵人在畫面中的時候隱藏箭頭
        arrow.enabled = !enemy.isVisible;
    }

    //更新UI箭頭圖片位置
    private void UpdateArrow(RectTransform r, Vector3 enemyWorldPos, UnityEngine.UI.Image arrow)
    {
        Vector2 enemyUIPos = UIPosition.WorldToUI(r, enemyWorldPos); //怪物世界座標轉換成UI座標

        float width = r.rect.width / 2; //UI一半的寬,因為原點在中心
        float height = r.rect.height / 2; //UI一半的高
        Vector2 uiPos = new Vector2(Mathf.Clamp(enemyUIPos.x, -width, width), Mathf.Clamp(enemyUIPos.y, -height, height)); //限制Image的位置不要超出畫面

        arrow.rectTransform.localPosition = uiPos; //調整箭頭的位置
        float angle = Mathf.Atan2(uiPos.y, uiPos.x) * Mathf.Rad2Deg;
        arrow.rectTransform.localEulerAngles = new Vector3(0, 0, angle - 90); //簡單做個計算角度後調整箭頭讓箭頭朝向敵人,這邊因為箭頭圖片的頂端是在正上方所以angle要減90度
    }
}

  到這邊就完成了,把這個Component掛在物件上,然後把UI canvas的RectTransform跟箭頭的Image抓上去就可以了,敵人我是用個亂跑的球Mesh抓上去,需視情況修改使用。

  這邊要注意一個小問題,就是我這邊用MeshRenderer的isVisible來判斷是否出現在畫面中來隱藏或顯示箭頭,如果編輯Scene的視窗有看到這個物件,也會判斷是在鏡頭前,所以會發生Game視窗沒看到敵人,但箭頭卻隱藏了。

  如果有任何問題或錯誤歡迎提出。



Unity - 物件世界座標(World position) <-> UI座標(UGUI position)的互換

  簡單的來做個座標的轉換,雖然不一定會常常用到,但是某些地方還是有點小用處就是了。


  這次就是把UGUI中的Local物件座標跟世界座標來做個轉換。

Unity - 取得Android手機中的AssetBundle來使用 (使用Unity的API)

  取得Android手機中保存的資料並且載入到遊戲中,之前有發過一篇(Unity - 取得Android手機中的圖檔來做為材質),使用的方法是製作自己的PlugIn,目的在於內部java抓取資料傳送給Unity並使用,不過如果只是要讀取某些下載的檔案像是Bundle之類的,可以不用這麼麻煩。

  簡單來說可以用Application.persistentDataPath來取得你存放檔案的位置,或者是你明確的知道該檔案放在外部SD卡的哪個資料夾下,接著都可以用WWW來讀取該物件,讀取完畢後再看是要怎麼做就行了。

Unity - PuzzleGame 5 (接水管接電線)

  接電線或是接水管類型的遊戲,大致上就是有一個可以調整的盤面,上面有許多格子可以旋轉,不一定是正方形,不過這邊簡單製作用正方形比較方便,格子上會有一些路徑,旋轉格子讓這些路徑連接起來。

  通常會有一個起點一個終點,既然這邊是接電線,起點就是電源,終點就用電燈,當路徑從起點到終點有達成連線的時候,遊戲就完成了。



  製作這個我覺得可以有幾種做法,一種就是亂數安排路徑,好處是每次結果都會不同,但是壞處就是難度比較無法掌控;另一種就是預先把版面設計幾種,好處就是可以掌控電線的路徑圖案跟難度,壞處就是要花時間把版面設定完畢,而且變化不大,重玩幾次就可以背下答案。

  這邊使用的亂數安排路徑,因為比較省時間,另外也可以使用之前做過的迷宮產生器來產生路線資料。