Unity中如何用鼠标(mouse)优雅的把一坨物体拖动(drag)旋转

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

它们都是沿着自身的某两个轴进行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);
    }
}
   
  • 9
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
### 回答1: Unity是一个功能强大的游戏引擎,可用于创建各种2D和3D游戏。在Unity,拖拽旋转物体是一个常见的需求,可以通过以下步骤实现。 首先,通过添加组件将对象转化为可挂接的对象。可以挂接一个刚体组件或是使用物理引擎,也可以使用脚本控制其移动和旋转。 然后,鼠标右键单击对象,选择“3D对象”、“空物体”或“其他”选项。这将创建一个空对象,它将成为控制器。将控制器命名为“旋转控制器”。 接着,将对象拖到旋转控制器上,并将其调整到对象的心点。这样一来,我们就可以通过拖拽旋转控制器来旋转对象。还可以通过缩放控制器来改变对象的大小,通过移动控制器来移动对象。 最后,在脚本添加代码来控制旋转控制器。例如,可以编写代码使控制器沿着Y轴旋转,或根据鼠标的拖拽来旋转控制器。还可以使用键盘控制器来旋转控制器。 以上步骤可帮助你在Unity实现拖拽旋转物体的效果。掌握了这些技能,你将能够创建出更加复杂而精彩的游戏。 ### 回答2: Unity拖拽旋转物体非常简单。首先,我们需要在场景创建一个物体,比如一个立方体。然后,我们将其选择并拖拽到层次结构视图。接着,我们点击场景视图的立方体,从而选择它。 现在,我们可以在场景视图看到三个箭头。分别是红、绿和蓝色的箭头,代表了物体在空间的X、Y和Z轴。我们可以通过拖拽这些箭头来移动物体,也可以通过点击物体旁边的圆圈来旋转物体。我们可以按住鼠标左键来旋转物体,也可以按住鼠标右键来平移物体。按住鼠标键可以放大和缩小物体。 如果需要更精确的控制,我们可以使用GameObject菜单旋转和平移选项,或者使用快捷键W(移动)、E(旋转)和R(缩放)。 总之,Unity的拖拽旋转物体非常方便,可以通过鼠标和快捷键来进行控制,从而快速创建我们需要的场景。 ### 回答3: Unity引擎是一款非常强大的游戏开发引擎,它支持多种交互功能,其最基本的是拖拽和旋转物体。 拖拽物体需要用到Unity的Transform组件,它是每个游戏物体上都有的组件。拖拽物体,首先需要确保选了合适的物体,并且该物体的Transform组件被打开。在场景视图点击选物体,然后可以通过点击并拖拽标识该物体的小圆圈,来将物体移动到新的位置。同时,可以在Inspector面板手动修改该物体的Position属性值来实现位置的修改。 旋转物体也需要用到Transform组件。在场景视图需要旋转物体,在该物体的Transform组件找到Rotation属性。通过手动修改该属性的值或者直接在场景视图点击并拖动物体上的小圆球来旋转物体。 需要注意的是,旋转的方向会根据圆球的位置而不同,例如,在圆球上方旋转时,物体会围绕X轴旋转;在圆球左边旋转时,物体会围绕Y轴旋转;在圆球前方旋转时,物体会围绕Z轴旋转。 以上就是Unity拖拽旋转物体的基本操作方法。通过这些方法,可以轻松实现游戏物体的移动和旋转功能,为游戏开发带来更多的交互性和用户体验。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值