Unity3D 学习手记 - UGUI

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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的勾去掉。

 

完整代码:

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);
    }
}

 

以上是关于Unity3D 学习手记 - UGUI的主要内容,如果未能解决你的问题,请参考以下文章

Unity3D基础让物体动起来①--UGUI鼠标点击移动

Unity3D——使用UGUI制作小地图

Unity3d UGUI 通用Confirm确认对话框实现(Inventory Pro学习总结)

Unity3d UGUI序列帧动画

Unity3D中UGUI不使用DOTween制作渐隐渐现效果

Unity3d — — UGUI之Box Collider自适应大小