引言
最近的项目中需要开发虚拟摇杆功能,由于历史原因对于FingerGesture较为熟悉,故没有采用EasyTouch。
NGUI中的UIDragObject
NGUI中有一个UIDragObject.cs组件,添加到GameObject,即可实现简单的拖拽动作。
其中的Target需要设置被拖拽的对象,代码注释如下:
/// <summary>
/// Target object that will be dragged.
/// </summary>
public Transform target;
仅仅添加该组件是不够的,想要捕获鼠标事件还需要在对象上添加Box Collider组件。
运行项目,就可以拖拽对象了。
分析虚拟摇杆需求
首先要虚拟摇杆分为两部分,中间一小部分为中间的滑块,周围一圈是背景层。(资源是EasyTouch里的)
操作同时也分为两种情况:
1.拖拽中间的滑块;
2.直接点击周围的背景部分,滑块直接跳转到对应位置。
返回什么?
操作虚拟摇杆只需返回一个Vector3向量即可(从原点指向滑块被拖拽位置,其实是一个二维向量,z值没有用到。)
代码实现
对于滑块部分的操作可以借鉴NGUI中的UIDragObject的实现,只需保留最基本的功能,只用到了NGUI中的OnPress和OnDrag事件。
滑块部分代码如下:
using UnityEngine;
using System.Collections;
public class JoyStickDragObject : MonoBehaviour
{
public Transform target;
Vector3 mTargetPos; // 目标当前位置
Vector3 mLastPos;
int mTouchID = 0;
bool mStarted = false;
bool mPressed = false;
[SerializeField]
protected Vector3 scale = new Vector3(1f, 1f, 0f);
protected Vector3 originPos = Vector3.zero;
protected Vector3 offsetFromOrigin = Vector3.zero; // 原点到拖拽位置的向量
public Vector3 OffsetFromOrigin
{
set { offsetFromOrigin = value; }
get { return offsetFromOrigin; }
}
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void OnPress(bool pressed)
{
if (enabled && NGUITools.GetActive(gameObject) && target != null)
{
if (pressed)
{
if (!mPressed)
{
mTouchID = UICamera.currentTouchID;
mPressed = true;
mStarted = false;
CancelMovement();
}
}
else if (mPressed && mTouchID == UICamera.currentTouchID)
{
mPressed = false;
target.position = Vector3.zero;
}
}
}
void OnDrag(Vector2 delta)
{
Ray ray = UICamera.currentCamera.ScreenPointToRay(UICamera.currentTouch.pos);
float dist = 0f;
Vector3 currentPos = ray.GetPoint(dist);
///< 更新当前坐标到上一时刻坐标的向量
Vector3 offset = currentPos - mLastPos;
///< 更新当前坐标到原点的向量
UpdateVector3FromOrigin(currentPos);
mLastPos = currentPos;
if (!mStarted)
{
mStarted = true;
offset = Vector3.zero;
}
Debug.LogWarning("offset: " + offset + " OffsetFromOrigin: " + OffsetFromOrigin);
Move(offset);
}
void Move(Vector3 moveDelta)
{
mTargetPos += moveDelta;
target.position = mTargetPos;
}
void CancelMovement()
{
if (target != null)
{
Vector3 pos = target.localPosition;
target.localPosition = pos;
}
mTargetPos = (target != null) ? target.position : Vector3.zero;
}
///< 更新当前坐标到原点的向量
void UpdateVector3FromOrigin(Vector3 pos)
{
OffsetFromOrigin = pos - originPos;
}
}
背景层的处理与滑块部分略有不同,主要在于点击背景层,滑块需要直接移动到点击位置
背景层代码如下:
using UnityEngine;
using System.Collections;
public class JoyStickBackground : MonoBehaviour
{
public Transform thumb;
private bool isReset = true;
[SerializeField]
protected Vector3 originPos = Vector3.zero; // 原点
protected Vector3 offsetFromOrigin = Vector3.zero; // 原点到拖拽位置的向量
public Vector3 OffsetFromOrigin
{
set { offsetFromOrigin = value; }
get { return offsetFromOrigin; }
}
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
}
void OnPress(bool pressed)
{
if (pressed)
{
Ray ray = UICamera.currentCamera.ScreenPointToRay(UICamera.currentTouch.pos);
float dist = 0f;
Vector3 currentPos = ray.GetPoint(dist);
thumb.position = currentPos;
isReset = false;
///< 更新当前坐标到原点的向量
UpdateVector3FromOrigin(currentPos);
}
else
{
thumb.position = Vector3.zero;
isReset = true;
}
}
void OnDrag(Vector2 delta)
{
Ray ray = UICamera.currentCamera.ScreenPointToRay(UICamera.currentTouch.pos);
float dist = 0f;
Vector3 currentPos = ray.GetPoint(dist);
thumb.position = currentPos;
}
///< 更新当前坐标到原点的向量
void UpdateVector3FromOrigin(Vector3 pos)
{
OffsetFromOrigin = pos - originPos;
}
}
效果图:
拖拽滑块:
点击背景: