一、网上能见到的拖拽旋转代码
它们都是沿着自身的某两个轴进行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);
}
}