Unity基于NGUI的简单并可直接使用的虚拟摇杆实现(一)
可能大家都听说过大名鼎鼎的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博客发布作者和博客园作者为同一作者,特此说明】