可能大家都聽說過大名鼎鼎的easytouch,然而easytouch是基於UGUI的,兩種不同的UI混用,可能會造成項目管理的混亂,並且可能會出現各種幺蛾子,比如事件傳遞互相擾亂的問題。
於是就想找一種基於NGUI的搖桿,搜索網上的文章,都有很多問題,總結來說三個問題很突出。
一:代碼本事存在缺陷或者BUG,或者想得太簡單,比如沒有考慮手指相對按鈕的偏移,造成實際並不實用,只能用來學習。
二:號稱是NGUI的搖桿,但是有些實現卻用了UGUI的東西。
三:未考慮通用性,參數都是固定值,什么43啊73啊,都不知道這些值怎么來的。
於是自己寫吧,NGUI怎么用就不教了。
①首先,創建兩個Sprite(我這里偷懶用了2DSprite,因為不用打包圖片)和一個Texture。

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成員上。

⑥增加一個事件觸發器,NGuiJoystickArea->Add Component->NGUI->Interaction->Event Trigger。
⑦將Thumb拖到觸發器press事件上,並設置響應函數為startTouch();將Thumb拖到觸發器release事件上,並設置響應函數為endTouch()。

【預覽】

過幾天再上傳和人物的關聯文章,實現EasyTouch的allow turn and move,已經DeadValue等一些配置參數。
【本文為原創文章,CSDN博客發布作者和博客園作者為同一作者,特此說明】
