Unity3D 學習手記 - UGUI


  注:本實例開發環境為Unity 5.3.4,開發語言為C#

  這周的任務是用UGUI實現NGUI的一個效果:

  http://www.tasharen.com/ngui/exampleX.html

 

實現效果:

 

1. 格子是什么?其實是個按鈕!

項目分級:

頂層:InventoryMenu空對象,下屬InventoryMenuCam - UI攝像機,MenuManager - 管理類,ICanvas - UI畫布

ICanvas下屬:角色3D模型(從商店下載),Window - 控制Equip和Backpack面板

 

Equip: 下屬三個格子,分別對應頭部,上身和足部三種類別的盔甲

Backpack:下屬九個格子,可以放任意類別的盔甲

 

Grid:實際上是個按鈕 - OnClick()上掛載UIManager.mouseClickHandler(GameObject),對象上還掛在了一個Grid的MonoBehavior腳本,里面只有一個公共值 - GridNumber

設置Grid Number對應自身的格子編號。

設置OnClick傳遞自身對象為參數。

(對每個格子進行如上操作 - 我覺得會有更好的解決辦法?)

那這時每當按到這個格子的時候就會調用一次UIManager的mouseClickHandler()方法,這是會將自身對象作為一個參數發送給UIManager。

mouseClickHandler()里為不同情況下的點擊處理做了定義:

public void mouseClickHandler(GameObject gridObject) {
        int gridNumber = gridObject.GetComponent<Grid>().gridNumber;//0 - 2 is the equipment grid number
        if (gridNumber >= 0 && gridNumber <= 2) {
            if (im.isEquipmentGridOcupied (gridNumber)) {
                if (mouseInventType == 0) {
                    int equipmentType = im.getEquipmentInventory (gridNumber);
                    toggleImageFromGridToMouse (gridObject);
                    mouseInventType = equipmentType;
                }
            } else {
                //Grid 0 for head gear, 1 for chest gear, 2 for foot gear
                if (mouseInventType == 1 && gridNumber == 0) {
                    im.putInventoryonEqupment (gridNumber, mouseInventType);
                    toggleImageFromMouseToGrid (gridObject);
                    mouseInventType = 0;
                } else if (mouseInventType == 2 && gridNumber == 1) {
                    im.putInventoryonEqupment (gridNumber, mouseInventType);
                    toggleImageFromMouseToGrid (gridObject);
                    mouseInventType = 0;
                } else if (mouseInventType == 3 && gridNumber == 2) {
                    im.putInventoryonEqupment (gridNumber, mouseInventType);
                    toggleImageFromMouseToGrid (gridObject);
                    mouseInventType = 0;
                }

            }
        }
        //3 - 11 is the backpack grid number
        else if (gridNumber >= 3 && gridNumber <= 11) {
            int backPackGridNumber = gridNumber - 3;
            Debug.Log (backPackGridNumber + im.isBackpackGridOccupied(backPackGridNumber).ToString() + mouseInventType);
            if (im.isBackpackGridOccupied (backPackGridNumber)) {
                if (mouseInventType == 0) {
                    int inventoryType = im.getBackPackInventory (backPackGridNumber);
                    toggleImageFromGridToMouse (gridObject);
                    mouseInventType = inventoryType;
                } 
            } else {
                if (mouseInventType != 0) {
                    im.putBackPackInventory (backPackGridNumber, mouseInventType);
                    toggleImageFromMouseToGrid (gridObject);
                    mouseInventType = 0;
                }
            }
        }
    }

 

2. 界面邏輯和游戲邏輯的分離:UIManager和InventoryManager

你已經注意到了,界面里面我沒有對Grid細分為EquipmentGrid和BackpackGrid。這是考慮到從界面的角度來看,他們其實是同一種對象。

我另外實現了單實例對象InventoryManager,專門負責物品邏輯的管理:

 

如果要從外部來啟動這個菜單,應該由UIManager來發起初始化界面,再調用InventoryManager的Init方法初始化邏輯。這里為了簡便在UIManager中把初始化的物品列表設為公共。

一些初期設定:

 

3. 雜項

界面隨鼠標移動的實現方法,別忘了在人像上也掛載喔!

using UnityEngine;

public class TiltWindow : MonoBehaviour
{
    public Vector2 range = new Vector2(5f, 3f);

    Transform mTrans;
    Quaternion mStart;
    Vector2 mRot = Vector2.zero;

    void Start ()
    {
        mTrans = transform;
        mStart = mTrans.localRotation;
    }

    void Update ()
    {
        Vector3 pos = Input.mousePosition;

        float halfWidth = Screen.width * 0.5f;
        float halfHeight = Screen.height * 0.5f;
        float x = Mathf.Clamp((pos.x - halfWidth) / halfWidth, -1f, 1f);
        float y = Mathf.Clamp((pos.y - halfHeight) / halfHeight, -1f, 1f);
        mRot = Vector2.Lerp(mRot, new Vector2(x, y), Time.deltaTime * 5f);

        mTrans.localRotation = mStart * Quaternion.Euler(-mRot.y * range.y, -mRot.x * range.x, 0f);
    }
}

 

圖像隨鼠標移動的方法:

新建一個對象,ItenOnMouse,里面有個Image組件。讓這個組件無時無刻跟着鼠標走就行了。需要的時候enable,不需要的時候disable。

當然,由於在Canvas里用的是RectTransform,我們也必須用RectTransform,LocalPoint相關的方法來處理:

    void Update() {

        Vector2 mousePosWorld;

        RectTransformUtility.ScreenPointToLocalPointInRectangle (ICanvas.transform as RectTransform, Input.mousePosition, UICamera.GetComponent<Camera>(), out mousePosWorld);

        ImageOnMouseObj.transform.position = ICanvas.transform.TransformPoint (mousePosWorld);

    }

怎么防止ImageOnMouseObj擋着鼠標按按鈕?

將Raycast Target的勾去掉。

 

按鈕的狀態:

為按鈕加載動畫控制器Button

這些Trigger,對應着控制器中的Trigger名字

控制器設計:

Highlighted 上的動作:

HoverEnter,掛在在Highlighted

HoverExit,掛載在Normal

Loop Time的勾都去掉

Button的Navigation屬性勾去掉

 

完整代碼:

UIManager:

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class UIManager : MonoBehaviour {

    public int[] equipmentList = {1, 2, 3};
    public int[] backPackInvnetoryList = { 1, 2, 3, 0, 0, 0, 0, 0, 0 };

    public GameObject UICamera;
    public GameObject ICanvas;

    InventoryManager im = InventoryManager.getInstance();

    //following Invent Type convension
    int mouseInventType = 0;
    public GameObject ImageOnMouseObj;
    Image ImageOnMouse;

    public Sprite defaultSprite;

    void Start() {

        ImageOnMouse = ImageOnMouseObj.GetComponent<Image>();
        ImageOnMouseObj.SetActive (false);

        im.init (equipmentList, backPackInvnetoryList);
    }

    void Update() {

        Vector2 mousePosWorld;

        RectTransformUtility.ScreenPointToLocalPointInRectangle (ICanvas.transform as RectTransform, Input.mousePosition, UICamera.GetComponent<Camera>(), out mousePosWorld);

        ImageOnMouseObj.transform.position = ICanvas.transform.TransformPoint (mousePosWorld);

    }

    public void mouseClickHandler(GameObject gridObject) {
        int gridNumber = gridObject.GetComponent<Grid>().gridNumber;

        //0 - 2 is the equipment grid number
        if (gridNumber >= 0 && gridNumber <= 2) {
            if (im.isEquipmentGridOcupied (gridNumber)) {
                if (mouseInventType == 0) {
                    int equipmentType = im.getEquipmentInventory (gridNumber);
                    toggleImageFromGridToMouse (gridObject);
                    mouseInventType = equipmentType;
                }
            } else {
                //Grid 0 for head gear, 1 for chest gear, 2 for foot gear
                if (mouseInventType == 1 && gridNumber == 0) {
                    im.putInventoryonEqupment (gridNumber, mouseInventType);
                    toggleImageFromMouseToGrid (gridObject);
                    mouseInventType = 0;
                } else if (mouseInventType == 2 && gridNumber == 1) {
                    im.putInventoryonEqupment (gridNumber, mouseInventType);
                    toggleImageFromMouseToGrid (gridObject);
                    mouseInventType = 0;
                } else if (mouseInventType == 3 && gridNumber == 2) {
                    im.putInventoryonEqupment (gridNumber, mouseInventType);
                    toggleImageFromMouseToGrid (gridObject);
                    mouseInventType = 0;
                }

            }
        }
        //3 - 11 is the backpack grid number
        else if (gridNumber >= 3 && gridNumber <= 11) {
            int backPackGridNumber = gridNumber - 3;
            Debug.Log (backPackGridNumber + im.isBackpackGridOccupied(backPackGridNumber).ToString() + mouseInventType);
            if (im.isBackpackGridOccupied (backPackGridNumber)) {
                if (mouseInventType == 0) {
                    int inventoryType = im.getBackPackInventory (backPackGridNumber);
                    toggleImageFromGridToMouse (gridObject);
                    mouseInventType = inventoryType;
                } 
            } else {
                if (mouseInventType != 0) {
                    im.putBackPackInventory (backPackGridNumber, mouseInventType);
                    toggleImageFromMouseToGrid (gridObject);
                    mouseInventType = 0;
                }
            }
        }
    }


    void toggleImageFromGridToMouse(GameObject grid){
        Debug.Log (grid.name);
        Image ri_g = grid.GetComponent<Image>();
        ImageOnMouse.sprite = ri_g.sprite;
        ri_g.sprite = defaultSprite;

        Color color = ri_g.color;
        color.a = 0.78f;
        ri_g.color = color;

        Debug.Log (ri_g.color);

        ImageOnMouseObj.SetActive (true);

    }

    void toggleImageFromMouseToGrid(GameObject grid){
        ImageOnMouseObj.SetActive (false);
        Image ri_g = grid.GetComponent<Image>();

        Color color = ri_g.color;
        color.a = 1f;
        ri_g.color = color;

        ri_g.sprite = ImageOnMouse.sprite;
        ImageOnMouse.sprite = defaultSprite;

    }
        
}

 

InventoryManager:

using UnityEngine;
using System.Collections;

public class InventoryManager : System.Object {

    private static InventoryManager _instance;

    public static InventoryManager getInstance() {
        if (_instance == null) {
            _instance = new InventoryManager ();
        }
        return _instance;
    }

    int[] equipment;
    int[] backpack;

    public void init(int[] equipped, int[] backPackInventory){
        equipment = equipped;
        backpack = backPackInventory;
    }

    public bool isEquipmentGridOcupied (int equipmentGridNumber){
        if (equipmentGridNumber <= 2 && equipmentGridNumber >= 0) {
            if (equipment [equipmentGridNumber] != 0) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    public bool isBackpackGridOccupied (int inventoryGridNumber){
        //print_item ();
        if (backpack [inventoryGridNumber] != 0) {
            return true;
        } else {
            return false;
        }
    }

    public int getBackPackInventory(int backPackGridNumber){
        if (backPackGridNumber <= 8 && backPackGridNumber >= 0) {
            int inventoryType = backpack [backPackGridNumber];
            backpack [backPackGridNumber] = 0;
            //print_item ();
            return inventoryType;
        } else {
            return -1;
        }
    }

    public bool putBackPackInventory(int backPackGridNumber, int putInventoryType){
        if (backPackGridNumber <= 8 && backPackGridNumber >= 0) {
            backpack [backPackGridNumber] = putInventoryType;
            //print_item ();
            return true;
        } else {
            return false;
        }
    }

    public int getEquipmentInventory(int equipmentGridNumber){
        if (equipmentGridNumber <= 2 && equipmentGridNumber >= 0) {
            int equipmentInventoryType = equipment [equipmentGridNumber];
            equipment [equipmentGridNumber] = 0;
            //print_item ();
            return equipmentInventoryType;
        } else {
            return -1;
        }
    }

    public bool putInventoryonEqupment(int equipmentGridNumber, int inventoryType){
        //print_item ();
        if (equipmentGridNumber <= 2 && equipmentGridNumber >= 0) {
            equipment [equipmentGridNumber] = inventoryType;
            //print_item ();
            return true;
        } else {
            return false;
        }
    }

    void print_item(){
        Debug.Log ("Equipement: ");
        for (int i = 0; i < 3; i++) {
            Debug.Log (equipment[i] + " ");
        }
        Debug.Log ("Backpack: ");
        for (int i = 0; i < 9; i++) {
            Debug.Log (backpack[i] + " ");
        }
    }
}

 

Grid:

using UnityEngine;
using System.Collections;

public class Grid : MonoBehaviour {

    public int gridNumber = 0;

}

 

TiltWindow:

using UnityEngine;

public class TiltWindow : MonoBehaviour
{
    public Vector2 range = new Vector2(5f, 3f);

    Transform mTrans;
    Quaternion mStart;
    Vector2 mRot = Vector2.zero;

    void Start ()
    {
        mTrans = transform;
        mStart = mTrans.localRotation;
    }

    void Update ()
    {
        Vector3 pos = Input.mousePosition;

        float halfWidth = Screen.width * 0.5f;
        float halfHeight = Screen.height * 0.5f;
        float x = Mathf.Clamp((pos.x - halfWidth) / halfWidth, -1f, 1f);
        float y = Mathf.Clamp((pos.y - halfHeight) / halfHeight, -1f, 1f);
        mRot = Vector2.Lerp(mRot, new Vector2(x, y), Time.deltaTime * 5f);

        mTrans.localRotation = mStart * Quaternion.Euler(-mRot.y * range.y, -mRot.x * range.x, 0f);
    }
}

 


免責聲明!

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



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