* 作者:闪电Y黑客
* 日期: 2019.7.22
* 功能:计算出触摸拖拽后的位置
using SDHK_Tool.Static;
using UnityEngine;
using UnityEngine.EventSystems;
/*
* 作者:闪电Y黑客
*
* 日期: 2019.7.22
*
* 功能:计算出触摸拖拽后的位置
*
*/
namespace SDHK_Tool.Component
{
/// <summary>
/// 触摸位置计算器
/// </summary>
public class SC_TouchTransform : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler, IScrollHandler
{
/// <summary>
/// 电机接口(当电机不为空时,数值将会通过电机计算后再作用到物体上)
/// </summary>
private SI_TouchMotor TouchMotor;//电机接口
/// <summary>
/// 点击触摸池
/// </summary>
[Tooltip("触摸池")]
public SC_TouchPool_Down TouchPool_Down;
[Space()]
[Space()]
/// <summary>
/// 忽略鼠标事件
/// </summary>
[Tooltip("忽略鼠标")]
public bool IgnoreMouse = false;
/// <summary>
/// 触摸优先:优先使用最新的触摸点进行计算
/// </summary>
[Tooltip("触摸优先级")]
public bool TouchPriority = false;
/// <summary>
/// 计算结果直接作用于物体
/// </summary>
[Tooltip("拖拽结果作用于物体")]
public bool UseResults = true;
[Space()]
[Space()]
/// <summary>
/// 启用移动
/// </summary>
[Tooltip("移动")]
public bool Mobile = true;
/// <summary>
/// 启用旋转
/// </summary>
[Tooltip("旋转")]
public bool Rotation = true;
/// <summary>
/// 开启缩放
/// </summary>
[Tooltip("缩放")]
public bool Zoom = true;
[Space()]
[Space()]
/// <summary>
/// 触摸点数量限制
/// </summary>
[Tooltip("触摸点限制")]
public Vector2 TouchLimit = new Vector2(1, 10);
[Space()]
[Space()]
[Tooltip("调试触摸画线")]
public bool DebugLine = false;
//第一第二触摸位置
/// <summary>
/// 从点击池筛选出的第一个触摸点
/// </summary>
[System.NonSerialized]
public Vector2 Touch_First;
/// <summary>
/// 从点击池筛选出的第二个触摸点,移动禁止情况下为物体的中心点
/// </summary>
[System.NonSerialized]
public Vector2 Touch_Second;
//触摸拖拽刷新位置
/// <summary>
/// 拖拽时计算出的双指中心点
/// </summary>
[System.NonSerialized]
public Vector2 TouchCenterPointer;
/// <summary>
/// 拖拽时计算出的双指向量在世界坐标的角度
/// </summary>
[System.NonSerialized]
public float TouchAngle;
/// <summary>
/// 拖拽时计算出的双指向量缩放比例差值
/// </summary>
[System.NonSerialized]
public float TouchScale;
//触摸点之间的向量
/// <summary>
/// 双指向量
/// </summary>
[System.NonSerialized]
public Vector2 FirstToSecond;
private Vector2 FirstToSecond_Last;
//初始点击位置存档
/// <summary>
/// 每次点击时保存的双指中心点
/// </summary>
[System.NonSerialized]
public Vector2 Save_TouchCenterPointer;
/// <summary>
/// 每次点击时保存的双指向量角度
/// </summary>
[System.NonSerialized]
public float Save_TouchAngle;
/// <summary>
/// 每次点击时保存的双指向量长度
/// </summary>
[System.NonSerialized]
public float Save_TouchScale;
//初始点击偏差存档
/// <summary>
/// 每次点击时保存的双指中心点到物体中心的距离
/// </summary>
[System.NonSerialized]
public Vector2 Save_TouchCenterToTransform_Position;
/// <summary>
/// 每次点击时保存的双指角度与物体z轴的角度差
/// </summary>
[System.NonSerialized]
public float Save_TouchToTransform_Angle;
// private float Save_TouchToTransform_Scale;
//计算后的位置
/// <summary>
/// 计算拖拽后得到的位置
/// </summary>
[System.NonSerialized]
public Vector2 Transform_Position;
/// <summary>
/// 计算拖拽后得到的角度
/// </summary>
[System.NonSerialized]
public float Transform_Angle;
/// <summary>
/// 计算拖拽后得到的尺寸
/// </summary>
[System.NonSerialized]
public Vector3 Transform_Scale;
void Start()
{
TouchPool_Down //触摸池是必须要有的
= (GetComponent<SC_TouchPool_Down>() != null)
? GetComponent<SC_TouchPool_Down>()
: gameObject.AddComponent<SC_TouchPool_Down>()
;
Transform_Position = transform.position;
Transform_Angle = transform.eulerAngles.z;
Transform_Scale = transform.lossyScale;
}
/// <summary>
/// 设置电机
/// </summary>
/// <param name="TouchMotor">电机</param>
public void Set_TouchMotor(SI_TouchMotor TouchMotor)
{
this.TouchMotor = TouchMotor;
}
public void OnPointerDown(PointerEventData eventData)//点击事件
{
if (IgnoreMouse && eventData.pointerId < 0) return;//忽略鼠标
if (TouchPool_Down.TouchPool.Count < TouchLimit.x || TouchPool_Down.TouchPool.Count > TouchLimit.y) return;//触摸限制
TouchScreening();//稳定点筛选
FirstToSecond = Touch_Second - Touch_First; //当前手势向量
FirstToSecond_Last = FirstToSecond; //上一次的手势向量
//===================================
TouchCenterPointer = Touch_First + FirstToSecond * 0.5f; //当前手势中心点位置
Save_TouchCenterPointer = TouchCenterPointer; //手势中心位置存档
//当前手势向量角度 = 角度计算类.角度转换正负无限数值转换为正360度角(角度计算类.获得两个二维向量的角度差(二维向量.上,当前手势的向量,轴方向翻转));
TouchAngle = SS_EulerAngleConversion.Angle_PN_To_P360(SS_EulerAngleConversion.Get_Angle_In_Vector2Deviation(Vector2.up, FirstToSecond, false));
Save_TouchAngle = TouchAngle; //手势初始角度存档
Save_TouchScale = FirstToSecond.magnitude; //手势向量长度存档
Transform_Scale = transform.lossyScale; //缩放位置赋值
//触摸中心到本物体的向量存档 = 真实位置- 触摸中心位置存档;
Save_TouchCenterToTransform_Position = (Vector2)transform.position - Save_TouchCenterPointer;
//手势向量角度与本物体角度差值存档 = 数学类.计算角度差(触摸向量角度存档,物体真实角度);
Save_TouchToTransform_Angle = Mathf.DeltaAngle(Save_TouchAngle, transform.eulerAngles.z);
}
public void OnDrag(PointerEventData eventData)//拖拽事件
{
if (IgnoreMouse && eventData.pointerId < 0) return;//忽略鼠标
if (TouchPool_Down.TouchPool.Count < TouchLimit.x || TouchPool_Down.TouchPool.Count > TouchLimit.y) return;//触摸限制
TouchScreening();//稳定点筛选
FirstToSecond = Touch_Second - Touch_First;//手势向量计算
//===================================
TouchCenterPointer = Touch_First + FirstToSecond * 0.5f;//手势中心点位置
//当前手势向量角度 = 角度计算类.角度转换正负无限数值转换为正360度角(角度计算类.获得两个二维向量的角度差(二维向量.上,当前手势的向量,轴方向翻转));
TouchAngle = SS_EulerAngleConversion.Angle_PN_To_P360(SS_EulerAngleConversion.Get_Angle_In_Vector2Deviation(Vector2.up, FirstToSecond, false));
//缩放后的大小
if ((Zoom && !Mobile) || (Zoom && TouchPool_Down.TouchPool.Count > 1))
{
//缩放比例差值 = ((当前手势向量长度-上一次手势向量长度)/上一次手势向量长度)
TouchScale = ((FirstToSecond.magnitude - FirstToSecond_Last.magnitude) / FirstToSecond_Last.magnitude);
//缩放后的虚拟计算大小 += 缩放比例差值 * 当前虚拟大小;
Transform_Scale += TouchScale * Transform_Scale;
//缩放后的 触摸点到物体中心向量的存档 += 缩放比例差值 * 触摸点到物体中心向量的存档
if (Mobile) Save_TouchCenterToTransform_Position += TouchScale * Save_TouchCenterToTransform_Position;
}
//移动后的虚拟计算位置 = 触摸中心点 + 触摸中心点到物体中心向量存档;
if (Mobile) Transform_Position = TouchCenterPointer + Save_TouchCenterToTransform_Position;
//旋转后的虚拟计算位置 = 角度计算类.获取_位置_环绕旋转(环绕物:虚拟计算位置,环绕中心点:当前触摸手势中心点,轴向:世界坐标.z轴 ,旋转角度:数学类.获取角度差(手势角度存档,当前手势角度));
if (Mobile && Rotation) Transform_Position = SS_EulerAngleConversion.Get_Vector3_RotateRound(Transform_Position, TouchCenterPointer, Vector3.forward, Mathf.DeltaAngle(Save_TouchAngle, TouchAngle));
//物体旋转后的虚拟计算角度 = 手势角度与物体角度差存档 + 当前手势角度
if (Rotation) Transform_Angle = Save_TouchToTransform_Angle + TouchAngle;
//更新双指的向量值
FirstToSecond_Last = FirstToSecond;
}
public void OnPointerUp(PointerEventData eventData)//抬起事件
{
if (IgnoreMouse && eventData.pointerId < 0) return;//忽略鼠标
if (TouchPool_Down.TouchPool.Count < TouchLimit.x || TouchPool_Down.TouchPool.Count > TouchLimit.y) return;//触摸限制
TouchScreening();//稳定点筛选
FirstToSecond = Touch_Second - Touch_First; //当前手势向量
FirstToSecond_Last = FirstToSecond; //上一次的手势向量
//===================================
TouchCenterPointer = Touch_First + FirstToSecond * 0.5f; //当前手势中心点位置
Save_TouchCenterPointer = TouchCenterPointer; //手势中心位置存档
//当前手势向量角度 = 角度计算类.角度转换正负无限数值转换为正360度角(角度计算类.获得两个二维向量的角度差(二维向量.上,当前手势的向量,轴方向翻转));
TouchAngle = SS_EulerAngleConversion.Angle_PN_To_P360(SS_EulerAngleConversion.Get_Angle_In_Vector2Deviation(Vector2.up, FirstToSecond, false));
Save_TouchAngle = TouchAngle; //手势初始角度存档
Save_TouchScale = FirstToSecond.magnitude; //手势向量长度存档
//触摸中心到本物体的向量存档 =虚拟计算位置 - 触摸中心位置存档;
Save_TouchCenterToTransform_Position = Transform_Position - Save_TouchCenterPointer;
//手势向量角度与本物体角度差值存档 = 数学类.计算角度差(触摸向量角度存档,虚拟计算角度);
Save_TouchToTransform_Angle = Mathf.DeltaAngle(Save_TouchAngle, Transform_Angle);
}
public void OnScroll(PointerEventData eventData)//鼠标滚动
{
if (IgnoreMouse && eventData.pointerId < 0) return;//忽略鼠标
Transform_Scale = transform.lossyScale; //缩放位置赋值
//缩放比例差值 = ((当前手势向量长度-上一次手势向量长度)/上一次手势向量长度);
TouchScale = eventData.scrollDelta.y * 0.1f;
//缩放后的虚拟计算大小 +=缩放比例差值*当前虚拟大小;
Transform_Scale += TouchScale * Transform_Scale;
//缩放后的 触摸点到物体中心向量的存档 += ((当前手势向量长度-上一次手势向量长度)/上一次手势向量长度)*触摸点到物体中心向量的存档
if (Mobile) Save_TouchCenterToTransform_Position += eventData.scrollDelta.y * 0.1f * Save_TouchCenterToTransform_Position;
}
/// <summary>
/// 触摸点过滤:过滤计算出两个稳定点进行触摸计算
/// </summary>
private void TouchScreening()
{
if (TouchPool_Down.TouchPool.Count == 0) return;//忽略鼠标
if (!Mobile && (Rotation || Zoom)) //移动禁用情况
{
Touch_First = (TouchPriority)//触摸优先判断
? TouchPool_Down.TouchPool[TouchPool_Down.TouchIds[TouchPool_Down.TouchIds.Count - 1]].position//最后一个触摸点
: Touch_First = TouchPool_Down.TouchPool[TouchPool_Down.TouchIds[0]].position//第一个触摸点
;
Touch_Second = transform.position; //第二个触摸点为物体中心
}
else//开启移动情况
{
if (TouchPriority)//触摸优先判断
{
//优先筛选出最新的两个触摸点
Touch_First = (TouchPool_Down.TouchPool.Count < 2)
? TouchPool_Down.TouchPool[TouchPool_Down.TouchIds[TouchPool_Down.TouchIds.Count - 1]].position
: TouchPool_Down.TouchPool[TouchPool_Down.TouchIds[TouchPool_Down.TouchIds.Count - 2]].position
;
Touch_Second = TouchPool_Down.TouchPool[TouchPool_Down.TouchIds[TouchPool_Down.TouchIds.Count - 1]].position;
}
else
{
//使用最早的两个触摸点
Touch_First = TouchPool_Down.TouchPool[TouchPool_Down.TouchIds[0]].position;
Touch_Second = (TouchPool_Down.TouchPool.Count < 2)
? TouchPool_Down.TouchPool[TouchPool_Down.TouchIds[0]].position
: TouchPool_Down.TouchPool[TouchPool_Down.TouchIds[1]].position
;
}
}
}
void Update()
{
if (UseResults)//判断是否计算结果直接作用于物体
{
if (TouchMotor != null)//判断电机是否存在
{
transform.position = TouchMotor.TouchMortor_Mobile(Transform_Position);
transform.eulerAngles = new Vector3(0, 0, TouchMotor.TouchMortor_Rotation(Transform_Angle));
transform.localScale = TouchMotor.TouchMortor_Zoom(Transform_Scale);
}
else//不存在直接赋值
{
transform.position = Transform_Position;
transform.eulerAngles = new Vector3(0, 0, Transform_Angle);
transform.localScale = Transform_Scale;
}
}
if (DebugLine)
{
Debug.DrawLine(Touch_First, Touch_Second, Color.red);
Debug.DrawLine(Touch_First, Transform_Position, Color.green);
Debug.DrawLine(Touch_Second, Transform_Position, Color.green);
Debug.DrawLine(TouchCenterPointer, Transform_Position, Color.yellow);
}
}
}
}