EventSystem大家平时主要是用来处理UGUI的输入,但其实也可以使用在一般的3D对象上,Unity API对这个介绍的很少。
在网上找到了一篇介绍不错的文章。
https://www.cnblogs.com/weiqiangwaideshijie/p/6859867.html
以下是我的一些分享:
除了需要依赖UI相同的EventSystem之后,还需要使用Physics RayCaster组件绑定Camera上
Test脚本如下,只不过Drag事件还未处理,物体还不能拖动
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class TestSystemInputMono : MonoBehaviour, IPointerDownHandler, IBeginDragHandler, IDragHandler, IEndDragHandler {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
public void OnPointerDown (PointerEventData eventData)
{
Debug.Log ("OnPointerDown");
}
public void OnBeginDrag(PointerEventData data)
{
Debug.Log ("OnBeginDrag");
}
public void OnDrag(PointerEventData data)
{
Debug.Log ("OnDrag");
}
public void OnEndDrag(PointerEventData eventData)
{
Debug.Log ("OnEndDrag");
}
}
有关PointerEventData的参数,其中了些属性,很重要的
button | The InputButton for this event |
对应Mouse的三个按键
pointerId | Id of the pointer (touch id). |
对应Touch,这里还没有试过多点触屏是否支持,即是否支持同时拖拽两个物体
对对3D物体,最重要应该是PointerCurrentRaycast,其API说明:
https://docs.unity3d.com/ScriptReference/EventSystems.PointerEventData-pointerCurrentRaycast.html
depth | The relative depth of the element. |
distance | Distance to the hit. |
gameObject | The GameObject that was hit by the raycast. |
index | Hit index. |
isValid | Is there an associated module and a hit GameObject. |
module | BaseInputModule that raised the hit. |
screenPosition | The screen position from which the raycast was generated. |
sortingLayer | The SortingLayer of the hit object. |
sortingOrder | The SortingOrder for the hit object. |
worldNormal | The normal at the hit location of the raycast. |
worldPosition | The world position of the where the raycast has hit. |
其中worldPostion就是当前射线碰撞到的点的世界坐标。如果没有碰撞到,比如Drag时拖出物体区域,那isValid值为False
下面看如何进行Drag处理让其动起来
Vector3 oldPos;
public void OnDrag(PointerEventData data)
{
//Debug.Log ("OnDrag " + data.pointerCurrentRaycast.worldPosition + " valid " + data.pointerCurrentRaycast.isValid);
Debug.Log ("OnDrag " + data.delta);
//var newPos = Camera.main.ScreenToWorldPoint (new Vector3(data.position.x, data.position.y, Camera.main.nearClipPlane));
var newPos = data.pointerCurrentRaycast.worldPosition;
var offset = newPos - oldPos;
Debug.Log ("offset is " + offset);
var projectOffset = Vector3.ProjectOnPlane(offset, data.pointerCurrentRaycast.worldNormal);
transform.position += projectOffset;
//var dir2 = Camera.main.worldToCameraMatrix.inverse.MultiplyPoint (data.delta) - Camera.main.transform.position;
//
// var projectDir = Vector3.ProjectOnPlane(dir2, data.pointerCurrentRaycast.worldNormal);
// Debug.Log ("dir = " + dir2.ToString() + " projectDir = " + projectDir.ToString());
//TestAnchor.transform.position += projectDir;
oldPos = newPos;
}
大体思路是获取到在物体上的移动的相对偏移,再映射到拖拽的平面上,这里只是简单的取当前物体拖拽点平面。之前的思路有问题,想从Camera的屏幕相对位移出发,但不是想要的效果。