天天看點

Unity基于NGUI的簡單并可直接使用的虛拟搖杆實作(一)

可能大家都聽說過大名鼎鼎的easytouch,然而easytouch是基于UGUI的,兩種不同的UI混用,可能會造成項目管理的混亂,并且可能會出現各種幺蛾子,比如事件傳遞互相擾亂的問題。

于是就想找一種基于NGUI的搖杆,搜尋網上的文章,都有很多問題,總結來說三個問題很突出。

一:代碼本事存在缺陷或者BUG,或者想得太簡單,比如沒有考慮手指相對按鈕的偏移,造成實際并不實用,隻能用來學習。

二:号稱是NGUI的搖杆,但是有些實作卻用了UGUI的東西。

三:未考慮通用性,參數都是固定值,什麼43啊73啊,都不知道這些值怎麼來的。

于是自己寫吧,NGUI怎麼用就不教了。

①首先,建立兩個Sprite(我這裡偷懶用了2DSprite,因為不用打包圖檔)和一個Texture。

Unity基于NGUI的簡單并可直接使用的虛拟搖杆實作(一)

NGuiJoystick是搖杆的底盤,Thumb是搖杆的按鈕,NGuiJoystickArea用于Dynamic模式的顯示區域。

Dynamic模式:類似于EasyTouch插件的Dynamic模式,平時不顯示搖杆,手指按下在手指處顯示搖杆,放開手指搖杆消失。

注意:三個UI對象名字随意,但是層級關系不能錯。

②修改NGuiJoystick和Thumb的紋理圖檔并調整到你想要的合适大小(這裡最好長寬相等,因為不等我沒有試過行不行),給NGuiJoystick和Thumb都Attack上Collider。設定NGuiJoystick的depth為100,Thumb的depth為101(盡可能處于最上層,當然也可根據需求來改)。

③修改NGuiJoystickArea的大小(根據Dynamic模式下你想顯示的區域,我這裡鋪滿了全屏),Attack上Collider,修改NGuiJoystickArea的紋理(我這裡用了一張白色方向紋理),設定NGuiJoystickArea的color hint的值為(255,,255,255,50),修改depth為1(如果UIRoot和UICamera都是預設值0的話)。

④接下來就是代碼部分。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class JoyStickControl : MonoBehaviour
{
    public enum ShowType{Static,Dynamic}; //顯示模式
    public ShowType showType= ShowType.Static;
    public float radiusOffset = 0.0F; //半徑偏移值、用于圖檔問題造成的偏差進行微調
    public GameObject area = null;   //Dynamic模式下的顯示區域
    private float radius;       //底盤半徑
    private float ratio=1.0F;   //縮放值
    private bool isPress = false;   //是否是按下狀态
    private bool isFirstPress = false;  //是否第一次按下
    private Vector2 offset;  //手指相對于按鈕的偏移值

    private void Awake()
    {
        //擷取底盤半徑
        UI2DSprite parentSpirite = transform.parent.GetComponent<UI2DSprite>();
        float parentWidth = parentSpirite.width;
        radius = parentWidth / 2.0F+ radiusOffset;

        //擷取縮放值
        UIRoot root = GameObject.FindObjectOfType<UIRoot>();
        if (root != null)
        {
            // 實際尺寸和設計尺寸比例
            ratio = (float)root.activeHeight / Screen.height;
        }

        //如果是Dynamic模式、一開始隐藏搖杆、并将Area設定到近乎透明
        if (showType == ShowType.Dynamic)
        {
            transform.parent.gameObject.SetActive(false);
            if (area != null)
            {
                UITexture areaTexture = area.GetComponent<UITexture>();
                areaTexture.color = new Color(1.0F, 1.0F, 1.0F, 1.0F/255.0F);
            }
        }
        else
        {
            if (area != null)
            {
                area.SetActive(false);
            }
        }
    }

    // Update is called once per frame
    private void Update()
    {
        // 觸摸按下
        if (isPress)
        {
            //最後一次觸摸位置、基于螢幕坐标
            Vector2 touchpos = UICamera.lastEventPosition;
            //擷取搖杆按鈕的螢幕坐标
            Vector2 childCenterPos = UICamera.currentCamera.WorldToScreenPoint(transform.position);
            //第一次觸摸的時候擷取手指相對于按鈕的偏移值
            if (!isFirstPress)
            {
                offset = touchpos - childCenterPos;
                isFirstPress = true;
            }
            
            //擷取搖杆底盤的螢幕坐标
            Vector2 centerPos = UICamera.currentCamera.WorldToScreenPoint(transform.parent.position);

            //擷取touchpos - offset和centerPos之間的距離值
            //凡是用到touchpos - offset的地方絕對不能用childCenterPos替代、可以考慮下為什麼
            float distance = Vector2.Distance(touchpos - offset, centerPos);

            //如果距離小于半徑,則将按鈕位置移動到touchpos - offset位置
            //distance算到的相對距離,需要乘以縮放值
            if (distance * ratio < radius)// 距離在父精靈背景中圓内,radius為其半徑
            {
                Vector3 worldTouchPos = UICamera.currentCamera.ScreenToWorldPoint(touchpos - offset);
                transform.position = worldTouchPos;
            }
            //距離超過半徑、則把按鈕的位置設定在底盤的圓上
            else
            {
                transform.localPosition = (touchpos - offset - centerPos).normalized * radius;
                childCenterPos = UICamera.currentCamera.WorldToScreenPoint(transform.position);
            }

        }
        // 觸摸擡起、那麼把按鈕位置恢複到原點、 将isFirstPress置否,如果是Dynamic模式、還要隐藏搖杆
        else
        {
            if (showType == ShowType.Dynamic)
            {
                transform.parent.gameObject.SetActive(false);
            }
            transform.localPosition = Vector2.zero;
            isFirstPress = false;
        }
    }

    // 觸摸按下、isPress為true、擡起為false
    public void OnPress(bool isPress)
    { 
        this.isPress = isPress;
    }

    //用于Dynamic模式press事件的響應
    public void startTouch()
    {
        if (showType == ShowType.Dynamic)
        {
            transform.parent.gameObject.SetActive(true);
            Vector2 startTouchPos = UICamera.lastEventPosition;
            Vector2 startTouchWorldPos = UICamera.currentCamera.ScreenToWorldPoint(startTouchPos);
            transform.parent.position = startTouchWorldPos;
            this.isPress = true;
        }
    }

    //用于Dynamic模式release事件的響應
    public void endTouch()
    {
        if (showType == ShowType.Dynamic)
        {
            transform.parent.gameObject.SetActive(false);
        }
        transform.localPosition = Vector2.zero;
        isFirstPress = false;
    }
}      

⑤把腳本拖到thumb對象上,并且把NGuiJoystickArea拖到腳本的public成員上。

Unity基于NGUI的簡單并可直接使用的虛拟搖杆實作(一)

⑥增加一個事件觸發器,NGuiJoystickArea->Add Component->NGUI->Interaction->Event Trigger。

⑦将Thumb拖到觸發器press事件上,并設定響應函數為startTouch();将Thumb拖到觸發器release事件上,并設定響應函數為endTouch()。

Unity基于NGUI的簡單并可直接使用的虛拟搖杆實作(一)

【預覽】

Unity基于NGUI的簡單并可直接使用的虛拟搖杆實作(一)

過幾天再上傳和人物的關聯文章,實作EasyTouch的allow turn and move,已經DeadValue等一些配置參數。

【本文為原創文章,CSDN部落格釋出作者和部落格園作者為同一作者,特此說明】