实现拖拽物体到指定线框位置的效果
为了更明显展示用了发光插件Highlight Plus和线框材质,编辑器里除了要进行移动的物体外,目标位置都是用Cube。
挂载组件:
移动的物体:碰撞体(需要勾选触发器),刚体,发光组件(不激活)
目标物体:碰撞体,发光组件(目标物体组件全部不激活)
新建一个脚本用于控制物体拖拽,代码如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HighlightPlus;
public class OnDragObj : MonoBehaviour
{
public GameObject targeObj;//目标物体位置(初始隐藏)
bool allowDrag, isCollision;//是否允许拖拽,是否发生碰撞
public bool isArriveTarge;//是否到达目标位置
float h;//初始高度
float z;//初始深度
public void Start()
{
allowDrag = true;
IsEnableComponent<HighlightEffect>(transform, true);
h = transform.position.y;
z = transform.position.z;
}
private void OnMouseDrag()
{
if (allowDrag)
{
//如果开始拖拽,显示目标物体并激活其碰撞体组件和发光组件
targeObj.SetActive(true);
IsEnableBoxCollider(targeObj.transform,true);
IsEnableComponent<HighlightEffect>(targeObj.transform, true);
//存放鼠标位置
Vector3 mousePos = Input.mousePosition;
//将当前物体位置转换为屏幕坐标并赋值给鼠标位置,保证物体深度不会发生变化
mousePos.z = Camera.main.WorldToScreenPoint(transform.position).z;
//将鼠标位置转化为世界坐标
Vector3 objectPos = Camera.main.ScreenToWorldPoint(mousePos);
//限制该世界坐标高度不能小于初始高度
if (objectPos.y <= h)
{
objectPos.y = h;
}
//限制该世界坐标深度为物体初始深度
objectPos.z = z;
//给物体赋值坐标
transform.position = objectPos;
}
}
private void OnMouseUp()
{
//当鼠标抬起时,关闭目标物体的发光体组件
IsEnableComponent<HighlightEffect>(targeObj.transform, false);
if (isCollision)
{
//如果发生了碰撞不再允许拖拽,且让物体直接吸附到目标位置去,并关闭发光组件,目标物体消失,传出到达目标位置信息
allowDrag = false;
transform.position = targeObj.transform.position;
IsEnableComponent<HighlightEffect>(transform, false);
targeObj.SetActive(false);
isArriveTarge = true;
}
}
/// <summary>
/// 当触发器触发了,如果触发的碰撞体是目标物体就传出发生碰撞
/// </summary>
/// <param name="other"></param>
private void OnTriggerEnter(Collider other)
{
if (other.gameObject == targeObj)
isCollision = true;
}
private void OnTriggerExit(Collider other)
{
if (other.gameObject == targeObj)
isCollision = false;
}
/// <summary>
/// 是否激活对应组件
/// </summary>
/// <typeparam name="T">组件类型</typeparam>
/// <param name="tf">判断物体</param>
/// <param name="isEnable">布尔值</param>
public void IsEnableComponent<T>(Transform tf, bool isEnable) where T : MonoBehaviour
{
if (tf.TryGetComponent(out T component))
{
component.enabled = isEnable;
}
}
public void IsEnableBoxCollider(Transform tf,bool isEnable)
{
if (tf.TryGetComponent(out BoxCollider bx))
{
bx.enabled = isEnable;
}
}
}
以上基本就是拖拽需要用到的代码了,有需要的自行判断使用。
下面是项目中进行调用的方法,并没有另起脚本,所以只贴方法。
因为要依次调用所以脚本默认不激活,当激活的时候挂载的物体会激活发光组件
引擎内物体布置如下,Interaction是交互组,obj为被拖拽物体,Targe为目标物体
申明函数并挂载相应物体后,以队列前两个为一组,当拖拽完成后将其移除队列并开启下一组交互
public GameObject[] Interactions;//存放交互组
public List<OnDragObj> InteractionDrag = new List<OnDragObj>();//存放被拖拽物体
public UnityAction OnInteractionAfterEvent;//交互结束后事件
public UnityAction monoFunc; //帧事件
/// <summary>
/// 交互(队列前两个)
/// </summary>
/// <param name="callback">交互结束事件</param>
public void InteractionEvent(UnityAction callback)
{
//激活被拖拽物体身上的拖拽脚本
InteractionDrag[0].enabled = true;
InteractionDrag[1].enabled = true;
//设置交互结束事件
OnInteractionAfterEvent = callback;
//添加帧事件
monoFun+=InteractionOver;
}
/// <summary>
/// 交互结束
/// </summary>
/// <param name="callback"></param>
public void InteractionOver()
{
//当队列中的第一第二个物体都完成了拖拽,拖拽完成isArriveTarge为true
if (InteractionDrag[0].isArriveTarge && InteractionDrag[1].isArriveTarge)
{
//移除帧事件
monoFun-=InteractionOver;
//移除队列前两个物体
InteractionDrag.Remove(InteractionDrag[1]);
InteractionDrag.Remove(InteractionDrag[0]);
//执行交互结束事件
OnInteractionAfterEvent?.Invoke();
}
}
private void Update()
{
monoFunc?.Invoke();
}
调用方法
Interactions[0].SetActive(true);
InteractionEvent(() =>
{
Interactions[1].SetActive(true);
InteractionEvent(() =>
{
Interactions[2].SetActive(true);
InteractionEvent(() => 之后的事件);
});
});
实现效果图如下
/// <summary>
/// 交互(队列第一个)
/// </summary>
/// <param name="callback"></param>
public void InteractionEvent0(UnityAction callback)
{
InteractionDrag[0].enabled = true;
OnInteractionAfterEvent = callback;
monoFun+=InteractionOver0;
}
/// <summary>
/// 交互结束
/// </summary>
/// <param name="callback"></param>
public void InteractionOver0()
{
if (InteractionDrag[0].isArriveTarge)
{
monoFun-=InteractionOver0;
InteractionDrag.Remove(InteractionDrag[0]);
OnInteractionAfterEvent?.Invoke();
}
}
InteractionEvent0(() =>
InteractionEvent0(() =>
InteractionEvent0(() =>
InteractionEvent0(() =>
InteractionEvent0(() => 之后执行事件)))));
菜鸟程序一枚,第一次记录博客,写不清楚的地方还望见谅。