一、网上能见到的拖拽旋转代码

它们都是沿着自身的某两个轴进行rotate,代码通常如下:

float XaxisRotation = Input.GetAxis("Mouse X") * RotationSpeed;
//float XaxisRotation = Input.mousePosition.x * RotationSpeed;

float YaxisRotation = Input.GetAxis("Mouse Y") * RotationSpeed;
//float YaxisRotation = Input.mousePosition.y * RotationSpeed;

// 设置旋转的轴心和旋转的量
go.Rotate(Vector3.down, XaxisRotation);
go.Rotate(Vector3.right, -YaxisRotation);

结局:
第一次拖拽都是母慈子孝——拖它往左,它就往左转,拖它往右,它就往右转,but(一看见but你就应该想到,要反转了),当物体转到背面后,你会发现:你往左拖,它往右转…简直鸡飞狗跳…

请看下面的效果:
请添加图片描述

如何修改呢?

二、请先欣赏这种母慈子孝的拖动效果

如何?向左拖向左转,向下拖向下转,始终都不会乱!!!
请添加图片描述

  • 脚本的参数:
    在这里插入图片描述

三、实现的思路

  • 旋转前:beginDrag
    1、生成旋转的root
    2、root对正方向:lookAt摄像机
    3、绑定父子关系:要旋转的物体作为root的子物体

  • 旋转中:Drag
    1、旋转root,带动子物体旋转

  • 停止旋转:endDrag
    1、撤销父子关系
    2、销毁root

  • 什么时候拖呢
    如上所示,你发现当鼠标悬停到物体上的时候,物体变成红色,此时物体才能拖动

四、代码

using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using System;
using static txlib;
using UnityEngine.EventSystems;

/*******************************************
    旋转前:beginDrag
        1、生成旋转的root
        2、对正方向:正对摄像机
        3、绑定父子关系

   旋转中:Drag
        1、旋转root,带动子物体旋转

   停止旋转:endDrag
        1、撤销父子关系
        2、销毁root
    *****************************************/


/// <summary>
/// 鼠标拖拽物体进行旋转
/// </summary>
public class DragObjectRotate : MonoBehaviour
{
    /// <summary>
    /// 相机
    /// </summary>
    public Transform cam;

    /// <summary>
    /// 要旋转点的物体
    /// </summary>
    public Transform objectToRotate;

    /// <summary>
    /// 旋转的速度因子
    /// </summary>
    public float RotationSpeed;

    /// <summary>
    /// 旋转物体的root
    /// </summary>
    private Transform rotateRoot;

    /// <summary>
    /// 旋转物体的父物体
    /// </summary>
    private Transform parent;

    /// <summary>
    /// 子物体
    /// </summary>
    public List<GameObject> childrenObjs = new List<GameObject>();

    // Start is called before the first frame update
    void Start()
    {
        childrenObjs.Clear();
        childrenObjs = GetChildren(objectToRotate);

        //记录物体的parent
        parent = objectToRotate.parent;       

        //事件添加
        childrenObjs.ForEach(obj=> 
        {
            //添加组件——EventTrigger
            if (obj.GetComponent<EventTrigger>() == null)
            {
                obj.gameObject.AddComponent<EventTrigger>();
            }

            //添加BoxCollider组件
            if (obj.GetComponent<Collider>() == null)
            {
                obj.gameObject.AddComponent<BoxCollider>();
            }

            //开始拖拽事件绑定
            obj.GetComponent<EventTrigger>().AddListener(EventTriggerType.BeginDrag, (PointerEventData eventData) =>
            {
                Debug.Log($"BeginDrag:");
                rotateRoot = GameObject.CreatePrimitive(PrimitiveType.Sphere).transform;
                rotateRoot.position = objectToRotate.position;
                rotateRoot.LookAt(cam);
                rotateRoot.transform.localScale = new Vector3(50, 50, 50);
                objectToRotate.parent = rotateRoot;                
            });

            //结束拖拽事件绑定
            obj.GetComponent<EventTrigger>().AddListener(EventTriggerType.EndDrag, (PointerEventData eventData) =>
            {
                Debug.Log($"EndDrag:");
                objectToRotate.parent = parent;
                Destroy(rotateRoot.gameObject);
                obj.GetComponent<MeshRenderer>().material.color = Color.white;
            });

            //拖拽事件绑定
            obj.GetComponent<EventTrigger>().AddListener(EventTriggerType.Drag, (PointerEventData eventData) =>
            {
                Debug.Log($"Dragging......");
                RotateOjb(RotationSpeed, rotateRoot);
                //RotateOjb(RotationSpeed, objectToRotate);
            });

            //得着焦点
            obj.GetComponent<EventTrigger>().AddListener(EventTriggerType.PointerEnter, (PointerEventData eventData) =>
            {
                obj.GetComponent<MeshRenderer>().material.color = Color.red;
            });

            //失去焦点
            obj.GetComponent<EventTrigger>().AddListener(EventTriggerType.PointerExit, (PointerEventData eventData) =>
            {
                obj.GetComponent<MeshRenderer>().material.color = Color.white;
            });
        });       
    }

    /// <summary>
    /// 用鼠标来旋转物体
    /// </summary>
    /// <param name="RotationSpeed">旋转速度</param>
    /// <param name="go">旋转的物体</param>
    void RotateOjb(float RotationSpeed,Transform go)
    {
        float XaxisRotation = Input.GetAxis("Mouse X") * RotationSpeed;
        //float XaxisRotation = Input.mousePosition.x * RotationSpeed;

        float YaxisRotation = Input.GetAxis("Mouse Y") * RotationSpeed;
        //float YaxisRotation = Input.mousePosition.y * RotationSpeed;

        // 设置旋转的轴心和旋转的量
        go.Rotate(Vector3.down, XaxisRotation);
        go.Rotate(Vector3.right, -YaxisRotation);
    }   

#if UNITY_EDITOR
    [ContextMenu("获取物体的子物体测试")]
#endif 
    void Test()
    {
        childrenObjs = GetChildren(objectToRotate);
    }

    /// <summary>
    /// 获取子物体:包含渲染组件的物体
    /// </summary>
    /// <param name="root"></param>
    /// <returns></returns>
    public List<GameObject> GetChildren(Transform root)
    {
        return root.GetComponentsInChildren<Transform>().Where(x => x.GetComponent<MeshRenderer>() != null).Select(x => x.gameObject).ToList();
    }
}

五、备注:代码中用到的一个AddListener扩展方法【using static txlib;】

  • 1、定义的扩展方法
    /// <summary>
    /// 为EventTrigger的事件类型绑定Action方法
    /// ===============示例代码=================begin
    ///  GetComponent<EventTrigger>()
    ///  .AddListener(EventTriggerType.PointerEnter, (PointerEventData eventData) =>
    ///  {
    ///     Debug.Log($"当前Enter的物体:{p.seriseNo}");
    ///     endImage = p.go;
    ///  });
    /// ===============示例代码=================end
    /// </summary>
    /// <param name="trigger">EventTrigger组件对象</param>
    /// <param name="eventType">事件类型</param>
    /// <param name="listenedAction">要执行的方法</param>
    public static void AddListener(this EventTrigger trigger, EventTriggerType eventType, Action<PointerEventData> listenedAction)
    {
        EventTrigger.Entry entry = new EventTrigger.Entry();
        entry.eventID = eventType;
        entry.callback.AddListener(data => listenedAction.Invoke((PointerEventData)data));
        trigger.triggers.Add(entry);
    }
  • 扩展方法放到一个静态类里
public static class txlib
{
    /// <summary>
    /// 为EventTrigger的事件类型绑定Action方法
    /// ===============示例代码=================begin
    ///  GetComponent<EventTrigger>()
    ///  .AddListener(EventTriggerType.PointerEnter, (PointerEventData eventData) =>
    ///  {
    ///     Debug.Log($"当前Enter的物体:{p.seriseNo}");
    ///     endImage = p.go;
    ///  });
    /// ===============示例代码=================end
    /// </summary>
    /// <param name="trigger">EventTrigger组件对象</param>
    /// <param name="eventType">事件类型</param>
    /// <param name="listenedAction">要执行的方法</param>
    public static void AddListener(this EventTrigger trigger, EventTriggerType eventType, Action<PointerEventData> listenedAction)
    {
        EventTrigger.Entry entry = new EventTrigger.Entry();
        entry.eventID = eventType;
        entry.callback.AddListener(data => listenedAction.Invoke((PointerEventData)data));
        trigger.triggers.Add(entry);
    }
}
   
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐