引言
最近在开发项目中的双摇杆功能,即利用摇杆释放指向性或者区域性的技能。之前介绍过利用NGUI开发的虚拟摇杆功能Unity3d中利用NGUI实现虚拟摇杆,本次在上文的基础上介绍一下如何限制滑块的移动区域。
需求分析
在拖拽滑块的基础上,增加区域限制。拖拽到限制区域边缘时,滑块会有被拉回的动作。
先看效果图
黑色区域为panel的区域,可以看到拖拽滑块基本被限制在panel区域内。
如何实现
UIPanel.cs中ConstrainTargetToBounds中实际裁剪的区域是如何确定的呢?
ConstrainTargetToBounds()
|__CalculateConstrainOffset()
|__finalClipRegion
finalClipRegion的实现如下,可以看出是依据Clipping的类型而进行不同的裁剪区域计算。
进而可以查看Clipping相关的属性
mclipping默认为UIDrawCall.clipping.None,mClipRange默认区域为300f*200f的矩形区域。
可以通过修改这两项参数来改变finalClipRegion的最终结果。
设置方式:
第一种可以在代码中进行设置
第二种方法也可以直接在编辑器中设置
最后,上代码:
代码在Unity3d中利用NGUI实现虚拟摇杆的基础上扩展了panel,并调用了panel.ConstrainTargetToBounds接口,其他并无二致。
using UnityEngine;
using System.Collections;
public class JoyStickDragObject : MonoBehaviour
{
public Transform target;
public UIPanel panel; // 用于限制拖拽区域
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;
}
if (panel.ConstrainTargetToBounds(target, false)) //限制拖拽区域
{
//Debug.Log("OnDrag: ConstrainTargetToBounds");
CancelMovement();
}
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;
}
}