Unity 鼠標控制/手指控制 物體左右慣性滑動旋轉,上下限制角度一些腳本總結

總結一些物體慣性旋轉方式,項目中用到了第二種,也推薦旋轉相機,可以用一個單獨的相機照射模型。另外,觸控屏獲取 Input.GetAxis(“Mouse X”) 獲取不到,使用 Input.touches[0].deltaPosition.x 來代替。

物體自動旋轉

在這裏插入圖片描述
腳本放在 Cube 上

using UnityEngine;

//物體添加剛體,忽略重力

// 自動圍繞 Y 軸旋轉
public class Spin : MonoBehaviour
{
	public Vector3 rotationsPerSecond = new Vector3(0f, 0.1f, 0f);
	public bool ignoreTimeScale = false;

	Rigidbody mRb;
	Transform mTrans;

	void Start ()
	{
		mTrans = transform;
		mRb = GetComponent<Rigidbody>();
	}

	void Update ()
	{
		if (mRb == null)
		{
			ApplyDelta(ignoreTimeScale ? RealTime.deltaTime : Time.deltaTime);
		}
	}

	void FixedUpdate ()
	{
		if (mRb != null)
		{
			ApplyDelta(Time.deltaTime);
		}
	}

	public void ApplyDelta (float delta)
	{
		delta *= Mathf.Rad2Deg * Mathf.PI * 2f;
		Quaternion offset = Quaternion.Euler(rotationsPerSecond * delta);

		if (mRb == null)
		{
			mTrans.rotation = mTrans.rotation * offset;
		}
		else
		{
			mRb.MoveRotation(mRb.rotation * offset);
		}
	}
}

using UnityEngine;


public class RealTime : MonoBehaviour
{
	static RealTime mInst;

	float mRealTime = 0f;
	float mRealDelta = 0f;

	/// <summary>
	/// Real time since startup.
	/// </summary>

	static public float time
	{
		get
		{
#if UNITY_EDITOR
			if (!Application.isPlaying) return Time.realtimeSinceStartup;
#endif
			if (mInst == null) Spawn();
			return mInst.mRealTime;
		}
	}

	/// <summary>
	/// Real delta time.
	/// </summary>

	static public float deltaTime
	{
		get
		{
#if UNITY_EDITOR
			if (!Application.isPlaying) return 0f;
#endif
			if (mInst == null) Spawn();
			return mInst.mRealDelta;
		}
	}

	static void Spawn ()
	{
		GameObject go = new GameObject("_RealTime");
		DontDestroyOnLoad(go);
		mInst = go.AddComponent<RealTime>();
		mInst.mRealTime = Time.realtimeSinceStartup;
	}

	void Update ()
	{
		float rt = Time.realtimeSinceStartup;
		mRealDelta = Mathf.Clamp01(rt - mRealTime);
		mRealTime = rt;
	}
}

左右慣性滑動,上下滑動,同時有角度限制

在這裏插入圖片描述
腳本放在照射 Cube 的相機上,實際轉的是相機,不是模型。通過勾選腳本中的 Is Touch 選擇是鼠標操作還是觸控屏操作。
下面是觸控操作效果:
在這裏插入圖片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ModelTest : MonoBehaviour
{
    public Transform target;
    public bool _isTouch;
    public float distance = 5.0f;
    public float xSpeed = 120.0f;//X旋轉速度
    public float ySpeed = 120.0f;//Y旋轉速度
    public float yMinLimit = -20f;
    public float yMaxLimit = 80f;
    public float distanceMin = 0.5f;
    public float distanceMax = 15f;
    public float smoothTime = 2f;

    public float rotationYAxis = 0.0f;
    public float rotationXAxis = 0.0f;
    public float velocityX = 0.0f;
    public float velocityY = 0.0f;

    private float roteSpeed = 0;//旋轉速度

    private Vector2 oldPosition1;
    private Vector2 oldPosition2;

    private bool _isDistanceAnim;

    private float _msgDistance;

    private bool _isAutoRote;
    private Vector3 _mousePos;
    private bool _moveMouse;

    // Start is called before the first frame update
    void Start()
    {
        Vector3 angles = transform.eulerAngles;
        angles.x = 90;
        rotationYAxis = angles.y;
        rotationXAxis = angles.x;

        Init();
    }

    private void Init()
    {
        velocityX = 0;
        velocityY = 0;

        rotationYAxis = transform.rotation.eulerAngles.x;
        rotationXAxis = transform.rotation.eulerAngles.y;

        distance = distanceMax;
        roteSpeed = distanceMin * 0.2f;
    }



    // Update is called once per frame
    void LateUpdate()
    {
        if (target == null)
        {
            return;
        }

        if (_isTouch)
        {
            if (Input.touchCount == 1)
            {
                //旋轉
                Touch t = Input.GetTouch(0);
                if (t.phase == TouchPhase.Began)//有人操作旋轉
                {
                    _mousePos = t.position;
                    _isAutoRote = false;
                }
                if (t.phase == TouchPhase.Moved)
                {
                    float d = Vector3.Distance(t.position, _mousePos);
                    if (d > 50f)
                    {
                        //小於50,表示移動距離很小,防止觸摸屏誤觸點擊
                        Debug.Log(d);
                        //開始旋轉
                    }
                }
                if (t.phase == TouchPhase.Ended)
                {
                    //停止
                }

                velocityX += xSpeed * t.deltaPosition.x * roteSpeed * 0.02f;
                velocityY -= ySpeed * t.deltaPosition.y * roteSpeed * 0.02f;
            }
        }
        else
        {
            if (Input.GetMouseButtonDown(0))
            {
                //有人操作旋轉
                _isAutoRote = false;
                _mousePos = Input.mousePosition;
                _moveMouse = false;
            }
            if (Input.GetMouseButtonUp(0))
            {
                _moveMouse = false;
            }
            if (Input.GetMouseButton(0))
            {
                velocityX += xSpeed * Input.GetAxis("Mouse X") * distance * 0.2f;
                velocityY -= ySpeed * Input.GetAxis("Mouse Y") * distance * 0.2f;

                if (Vector3.Distance(_mousePos, Input.mousePosition) > 10f && !_moveMouse)
                {
                    _moveMouse = true;
                }
            }
        }

        rotationXAxis += velocityX;
        rotationYAxis += velocityY;
        rotationYAxis = ClampAngle(rotationYAxis, yMinLimit, yMaxLimit);
        Quaternion toRotation = Quaternion.Euler(rotationYAxis, rotationXAxis, 0);
        Quaternion rotation = toRotation;

        transform.rotation = toRotation;

        velocityX = Mathf.Lerp(velocityX, 0, Time.deltaTime * smoothTime);
        velocityY = Mathf.Lerp(velocityY, 0, Time.deltaTime * smoothTime);

        if (_isTouch)
        {
            Zoom();
        }
        else
        {
            if (!_isDistanceAnim)
            {
                distance = Mathf.Clamp(distance - Input.GetAxis("Mouse ScrollWheel") * ((distanceMax - distanceMin) * 0.1f), distanceMin, distanceMax);
                //縮放
            }
        }

        Vector3 negDistance = new Vector3(0.0f, 0.0f, -distance);
        Vector3 position = rotation * negDistance + target.position;
        transform.position = position;
    }


    private void Zoom()
    {
        if (Input.touchCount < 2)
        {
            return;
        }

        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))
            {
                if (distance > distanceMin)
                {
                    distance -= (distanceMax - distanceMin) * 0.1f;
                }
            }
            else
            {
                if (distance < distanceMax)
                {
                    distance += (distanceMax - distanceMin) * 0.1f;
                }
            }
            oldPosition1 = tempPosition1;
            oldPosition2 = tempPosition2;
        }
    }

    public static float ClampAngle(float angle, float min, float max)
    {
        if (angle < -360F)
            angle += 360F;
        if (angle > 360F)
            angle -= 360F;
        return Mathf.Clamp(angle, min, max);
    }

    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;
        }
    }
}

支持左右慣性旋轉

綁定在 Cube 上, Rot Target 也是自身。支持鼠標和手指滑動
在這裏插入圖片描述

using UnityEngine;
using System.Collections;

//操作方式
public enum ControlTypeTest
{
    mouseControl,
    touchControl,
}

public class Test : MonoBehaviour
{
    public ControlTypeTest controlType;
    public Transform rotTarget;

    //旋轉速度加成係數
    public float rotSpeedScalar=20f;
    private float currentSpeed = 0;
    private void Start()
    {
        float a = float.Parse("-0.1994895");
        Debug.Log(a);
    }
    void Update()
    {
        if (controlType == ControlTypeTest.mouseControl)
        {
            //鼠標操作
            if (Input.GetMouseButton(0))
            {
                //拖動時速度
                //鼠標或手指在該幀移動的距離*deltaTime爲手指移動的速度,此處爲Input.GetAxis("Mouse X") / Time.deltaTime
                //不同幀率下lerp的第三個參數(即混合比例)也應根據幀率而不同--
                //考慮每秒2幀和每秒100幀的情況,如果此參數爲固定值,那麼在2幀的情況下,一秒後達到目標速度的0.75,而100幀的情況下,一秒後則基本約等於目標速度
                currentSpeed = Mathf.Lerp(currentSpeed, Input.GetAxis("Mouse X") / Time.deltaTime,0.5f * Time.deltaTime);
            }
            else
            {
                //放開時速度
                currentSpeed = Mathf.Lerp(currentSpeed, 0, 0.5f * Time.deltaTime);
            }
        }
        else if (controlType == ControlTypeTest.touchControl)
        {
                
            //觸摸操作
            if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
            {
                //在安卓設備上也可以用Mouse X,根據實驗,touch[0].deltaPosition.x的值總是比Mouse X的值大很多,所以此處使用Mouse X
                currentSpeed = Mathf.Lerp(currentSpeed, Input.touches[0].deltaPosition.x / Time.deltaTime/15, 0.5f * Time.deltaTime);
                Debug.Log(1111);
            }
            else
            {
                //放開時速度
                currentSpeed = Mathf.Lerp(currentSpeed, 0, 0.5f * Time.deltaTime);
            }
        }
        rotTarget.Rotate(Vector3.down, Time.deltaTime * currentSpeed * rotSpeedScalar);
    }
}

上下左右自由慣性旋轉 使用 Rigidbody.AddTorque

在這裏插入圖片描述
手指觸摸,腳本放在 Cube 上。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test2 : MonoBehaviour
{
    #region Rigibody.AddTorque 慣性旋轉
    public Rigidbody rigid;
    float h;
    float v;
    Vector3 torque;
    private void Start()
    {
        //rigid = GetComponent<Rigidbody>();
    }
    void Update()
    {
        if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
        {
            //h = Input.GetAxis("Mouse X");
            //v = Input.GetAxis("Mouse Y");
            h = Input.touches[0].deltaPosition.x / 15;
            v = Input.touches[0].deltaPosition.y / 15;
            Debug.Log(h + "   " + v);
        }
        else
        {
            h = 0;
            v = 0;
        }
        torque = new Vector3(v, -h, 0);
    }
    private void FixedUpdate()
    {
        rigid.AddTorque(torque * 1, ForceMode.Force);


    }
    #endregion
    }

物體自動左右旋轉,有手指滑動,按照手指滑動運行,沒有手指,繼續自動轉

在這裏插入圖片描述
腳本綁定在 Cube 上,相機爲照射 Cube 的相機。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test2 : MonoBehaviour
{
#region
public Camera MainCamera;
public float ZoomMin;      //滾輪的最小值
public float ZoomMax;      //滾輪的最大值
private float normalDistance;   //設置攝像機的景深值
private float MouseWheelSencitivity = 10.0f;    //鼠標靈敏度,就是縮放的速度的快慢

private float axisX;
private float axisY;
public float speed = 6f;
private float tempSpeed;

private bool RoationOnly;

void Start()
{
    normalDistance = 50.0f;
    ZoomMin = 20.0f;
    ZoomMax = 100.0f;
    RoationOnly = true;
}


void Update()
{
    Roation();
    this.transform.Rotate(new Vector3(0, axisX, 0) * Rigid(), Space.World);     //物體旋轉的方法
}


//自動旋轉物體的方法,放在Update中調用
void Roation()
{
    if (RoationOnly)
    {
        gameObject.transform.Rotate(Vector3.up * Time.deltaTime * 10);
    }
}


/***
 * 
 * 鼠標左鍵控制物體360°旋轉+慣性
 * **/
float Rigid()
{
    if (Input.touchCount <= 0)
        return 0;
    //if (Input.GetTouch(0).phase == TouchPhase.Ended)
    //{

    //    transform.eulerAngles = new Vector3(0, transform.eulerAngles.y, 0);
    //}

    if (Input.GetTouch(0).phase == TouchPhase.Moved)
    {
        RoationOnly = false;    //當鼠標按下的時候,停止自動旋轉

        //axisX = Input.GetAxis("Mouse X");
        //axisY = Input.GetAxis("Mouse Y");
        axisX = Input.touches[0].deltaPosition.x / 30;
        axisY = Input.touches[0].deltaPosition.y / 30;
        if (tempSpeed < speed)
        {
            tempSpeed += speed * Time.deltaTime * 5;
        }
        else
        {
            tempSpeed = speed;
        }
    }
    else
    {
        RoationOnly = true;     //當鼠標沒有按下的時候,恢復自動旋轉
        if (tempSpeed > 0)
        {
            tempSpeed -= speed * Time.deltaTime;
        }
        else
        {
            tempSpeed = 0;
        }
    }


    return tempSpeed;
}
    #endregion
}
   
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章