这几天一直在做移动端手势方面的项目,现在把几种常见的方法总结一下。
1.通过手势控制物体大小进行缩放,这种实际上就是改变了物体的localScale 。这种方式常用于AR里面对物体的操作。
float distance = 30f;
float xSpeed = 50f;
float ySpeed = 50f;
float x = 0f;
float y = 0f;
Vector2 oldPosition1;
Vector2 oldPosition2;
private bool flag_Roable = true;//自动旋转标志
private AudioSource AudioSources;
private System.DateTime oldTime;
private System.DateTime nowTime;
void Start()
{
Vector3 angles = transform.eulerAngles;
x = angles.y;
y = angles.x;
oldTime = System.DateTime.Now;
}
void Update()
{
nowTime = System.DateTime.Now;
System.TimeSpan ts1 = new System.TimeSpan(oldTime.Ticks);
System.TimeSpan ts2 = new System.TimeSpan(nowTime.Ticks);
System.TimeSpan ts = ts2.Subtract(ts1).Duration();
if (ts.Seconds > 8 && !Input.anyKey)
{
flag_Roable = true;
oldTime = System.DateTime.Now;
}
if (Input.anyKey)
{
if (Input.touchCount == 1)
{
if (Input.GetTouch(0).phase == TouchPhase.Moved)
{
x = Input.GetAxis("Mouse X") * xSpeed;
transform.Rotate(Vector3.up * -x * Time.deltaTime, Space.Self);
}
}
if (Input.touchCount > 1)
{
if (Input.GetTouch(0).phase == TouchPhase.Moved && Input.GetTouch(1).phase == TouchPhase.Moved)
{
Vector2 tempPosition1 = Input.GetTouch(0).position;
Vector2 tempPosition2 = Input.GetTouch(1).position;
if (isEnlarge(oldPosition1, oldPosition2, tempPosition1, tempPosition2))
{
float oldScale = transform.localScale.x;
float newScale = oldScale * 1.025f;
transform.localScale = new Vector3(newScale, newScale, newScale);
}
else
{
float oldScale = transform.localScale.x;
float newScale = oldScale / 1.025f;
transform.localScale = new Vector3(newScale, newScale, newScale);
}
//备份上一次触摸点的位置,用于对比
oldPosition1 = tempPosition1;
oldPosition2 = tempPosition2;
}
}
}
}
bool isEnlarge(Vector2 oP1, Vector2 oP2, Vector2 nP1, Vector2 nP2)
{
//函数传入上一次触摸两点的位置与本次触摸两点的位置计算出用户的手势
var leng1 = Mathf.Sqrt((oP1.x - oP2.x) * (oP1.x - oP2.x) + (oP1.y - oP2.y) * (oP1.y - oP2.y));
var leng2 = Mathf.Sqrt((nP1.x - nP2.x) * (nP1.x - nP2.x) + (nP1.y - nP2.y) * (nP1.y - nP2.y));
if (leng1 < leng2)
{
//放大手势
return true;
}
else
{
//缩小手势
return false;
}
}
2.另一种方式是通过改变与摄像机的距离来改变物体的大小,这也是移动端常用的一种方法。
//用于绑定参照物对象
public Transform target;
//缩放系数
public float distance = 10.0f;
//左右滑动移动速度
public float xSpeed = 250.0f;
public float ySpeed = 120.0f;
//缩放限制系数
int yMinLimit = -80;
int yMaxLimit = 100;
//摄像头的位置
float x = 0.0f;
float y = 0.0f;
//记录上一次手机触摸位置判断用户是在左放大还是缩小手势
private Vector2 oldPosition1;
private Vector2 oldPosition2;
void Start()
{
var angles = transform.eulerAngles;
x = angles.y;
y = angles.x;
// Make the rigid body not change rotation
//if (rigidbody)
// rigidbody.freezeRotation = true;
}
void Update()
{
//判断触摸数量为单点触摸
if (Input.touchCount == 1)
{
//触摸类型为移动触摸
if (Input.GetTouch(0).phase == TouchPhase.Moved)
{
//根据触摸点计算X与Y位置
x += Input.GetAxis("Mouse X") * xSpeed * 0.02f;
y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
}
}
//判断触摸数量为多点触摸
if (Input.touchCount > 1)
{
//前两只手指触摸类型都为移动触摸
if (Input.GetTouch(0).phase == TouchPhase.Moved && Input.GetTouch(1).phase == TouchPhase.Moved)
{
//计算出当前两点触摸点的位置
var tempPosition1 = Input.GetTouch(0).position;
var tempPosition2 = Input.GetTouch(1).position;
//函数返回真为放大,返回假为缩小
if (isEnlarge(oldPosition1, oldPosition2, tempPosition1, tempPosition2))
{
distance -= 0.5f;
}
else
{
distance += 0.5f;
}
//备份上一次触摸点的位置,用于对比
oldPosition1 = tempPosition1;
oldPosition2 = tempPosition2;
}
}
}
//函数返回真为放大,返回假为缩小
bool isEnlarge(Vector2 oP1 , Vector2 oP2, Vector2 nP1,Vector2 nP2)
{
//函数传入上一次触摸两点的位置与本次触摸两点的位置计算出用户的手势
var leng1 = Mathf.Sqrt((oP1.x - oP2.x) * (oP1.x - oP2.x) + (oP1.y - oP2.y) * (oP1.y - oP2.y));
var leng2 = Mathf.Sqrt((nP1.x - nP2.x) * (nP1.x - nP2.x) + (nP1.y - nP2.y) * (nP1.y - nP2.y));
if(leng1<leng2)
{
//放大手势
return true;
}else
{
//缩小手势
return false;
}
}
//Update方法一旦调用结束以后进入这里算出重置摄像机的位置
void LateUpdate()
{
//缩放旋转的参照物
if (target)
{
//重置摄像机的位置
y = ClampAngle(y, yMinLimit, yMaxLimit);
var rotation = Quaternion.Euler(y, x, 0);
var position = rotation * Vector3.forward * (-distance) + target.position;
transform.rotation = rotation;
transform.position = position;
}
}
static float ClampAngle(float angle, float min, float max)
{
if (angle < -360)
angle += 360;
if (angle > 360)
angle -= 360;
return Mathf.Clamp(angle, min, max);
}
3.还有一种是根据一个PC端控制Camera操作的插件改写的一种移动端操作方式。这种操作方式模拟了PC端控制摄像机一样的旋转效果。适用于移动端较大的场景。
enum Axes { MouseXandY, MouseX, MouseY }
Axes Axis = Axes.MouseXandY;
public float sensitivityX = 3.0f;
public float sensitivityY = 3.0f;
float minimumX = -360.0f;
float maximumX = 360.0f;
float minimumY = -60.0f;
float maximumY = 0f;
float rotationX = 0.0f;
float rotationY = 0.0f;
public float scollspeed = 80f;
public float Key_movespeed = 1f;
public float Drag_movespeed = 100f;
float traX = 0f;
float traY = 0f;
public Camera cameraReference;
public float Max_X;
public float Min_X;
public float Max_Y;
public float Min_Y;
public float Max_Z;
public float Min_Z;
/// <summary>
/// 摄像机 transform 信息是否发生变化
/// </summary>
public bool isChange = false;
private Vector3 lastPosition;
private Vector3 lastEulerAngle;
private Vector2 oldPosition1;
private Vector2 oldPosition2;
void Update()
{
if (EventSystem.current.IsPointerOverGameObject(0))
{
return;
}
else
{
CameraMove();
JudgeIsChange();
if (Input.touchCount == 1)
{
if (Input.GetTouch(0).phase == TouchPhase.Moved)
{
FreeLook();
}
}
}
}
void JudgeIsChange()
{
if (lastPosition == cameraReference.transform.localPosition && lastEulerAngle == cameraReference.transform.localEulerAngles)
{
isChange = false;
}
else
{
isChange = true;
}
lastPosition = cameraReference.transform.localPosition;
lastEulerAngle = cameraReference.transform.localEulerAngles;
}
void CameraMove()
{
if (Input.GetAxis("Vertical") == 0 && Input.GetAxis("Horizontal") == 0)
{
return;
}
if (Input.touchCount == 1)
{
if (Input.GetTouch(0).phase == TouchPhase.Moved)
{
float translationZ = Input.GetAxis("Mouse Y") * Key_movespeed;
float translationX = Input.GetAxis("Mouse X") * Key_movespeed;
if (Mathf.Abs(translationZ) > Mathf.Abs(translationX))
{
//上下倾斜
transform.localPosition += cameraReference.transform.localRotation * new Vector3(0, 0, translationZ);
}
else
{
//水平旋转
transform.localPosition += cameraReference.transform.localRotation * new Vector3(translationX, 0, 0);
transform.position = new Vector3(Mathf.Clamp(transform.position.x, Min_X, Max_X), Mathf.Clamp(transform.position.y, Min_Y, Max_Y), Mathf.Clamp(transform.position.z, Min_Z, Max_Z));
}
}
}
else
{
}
}
void FreeLook()
{
if (Axis == Axes.MouseXandY)
{
// Read the mouse input axis
rotationX = transform.localEulerAngles.y + Input.GetAxis("Mouse X") * sensitivityX;
rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
// Call our Adjust to 360 degrees and clamp function
Adjust360andClamp();
// Most likely you wouldn't do this here unless you're controlling an object's rotation.
// Call our look left and right function.
KeyLookAround();
// Call our look up and down function.
KeyLookUp();
}
else if (Axis == Axes.MouseX)
{
// Read the mouse input axis
rotationX += Input.GetAxis("Mouse X") * sensitivityX;
// Call our Adjust to 360 degrees and clamp function
Adjust360andClamp();
KeyLookAround();
// Call our look up and down function.
KeyLookUp();
}
else
{
// Read the mouse input axis
rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
// Call our Adjust to 360 degrees and clamp function
Adjust360andClamp();
// Call our look left and right function.
KeyLookAround();
// Call our look up and down function.
KeyLookUp();
}
}
void KeyLookAround()
{
Adjust360andClamp();
// Transform our X angle
transform.localRotation = Quaternion.AngleAxis(rotationX, Vector3.up);
}
void KeyLookUp()
{
// Adjust for 360 degrees and clamp
Adjust360andClamp();
// Transform our Y angle, multiply so we don't loose our X transform
transform.localRotation *= Quaternion.AngleAxis(rotationY, Vector3.left);
}
void Adjust360andClamp()
{
if (rotationX < -360)
{
rotationX += 360;
}
else if (rotationX > 360)
{
rotationX -= 360;
}
// Don't let our Y go beyond 360 degrees + or -
if (rotationY < -360)
{
rotationY += 360;
}
else if (rotationY > 360)
{
rotationY -= 360;
}
// Clamp our angles to the min and max set in the Inspector
rotationX = Mathf.Clamp(rotationX, minimumX, maximumX);
rotationY = Mathf.Clamp(rotationY, minimumY, maximumY);
}
void Start()
{
// Make the rigid body not change rotation
if (GetComponent<Rigidbody>())
{
GetComponent<Rigidbody>().freezeRotation = true;
}
rotationX = transform.localEulerAngles.y;
rotationY = 0 - transform.localEulerAngles.x;
lastPosition = cameraReference.transform.localPosition;
lastEulerAngle = cameraReference.transform.localEulerAngles;
}