【Unity】在多个物体中选中一个,并高亮

效果如图

如何实现高亮?

我最开始脑子里想到的解决办法是:替换普通材质和边缘发光的材质,但是这样每个物体都有两个材质,太麻烦。

最后使用了HighlightingSystemDemo插件,这个网上资源很多的,大家随便下一下。人家是用屏幕特效的方式制作的,就可以很轻易地增加或删除,也不用对模型材质做任何改动!

具体使用方法,我直接翻译插件中PDF的教程了:

1. 把插件导入工程
2. 把HighlightingEffect.cs 脚本拖到摄像机上,并调整参数(默认就可以其实)
4. 把HighlightableObject.cs 脚本拖到需要高亮的物体上(若是多个物体的组合,则必须拖到根物体上)。 也可以在运行时动态添加该脚本。

这个高亮插件中定义了四种模式(按照优先级排序):
1. Occluder:被其他物体遮挡时,仍能看到轮廓光。
2. Once:字面上是只亮一次,例如鼠标移上时高亮,移开不高亮。
3. Flashing:字面意思是闪动,可以在两个颜色间闪烁(也可以改透明度)。在强调某些物体是可以用,比如新手教学。
4. Constantly:持续高亮。常用于标记被选中的物体。

如何实现在多个物体中选中一个?

首先我做了如下两种失败尝试:

1.用OnMouseEnter消息来实现鼠标移上的效果。结果发现这个函数的坑爹之处,使用时要注意以下3点:

1.代码:看代码有没有附加上要点击的物体上;
2.碰撞:要点击的物体加了碰撞,位置大小都对;而且鼠标屏幕点击的点和它之间没有其他的碰撞遮挡(OnMouseDown()原理利用了射线);(我的场景中有很多物体,而且碰撞盒都相互交织,无法准确选中我需要的物体。毕竟这些消息是作用于所有带碰撞盒的物体的,还不能选择Layer)
3.相关的摄像机上,有没有添加UICamera组件,NGUI里的UIcamera脚本点击会和OnMouseDown()相冲突。

2.用摄像机发出射线。的确可以选中一个物体,但是我想要选中另外一个物体时,很难让其他没有被选中的物体的高亮消失。如果用数组来管理所有曾被选中的物体:每次选中1个物体,就要手动对没有被选中的其他所有物体进行操作。这不禁让我想到了UGUI中的Toggle,不知道它内部是怎么实现选项之间的互斥的呢,肯定也是数组的方法。

这里也有关于Ray要注意的一个点:

--这段内容来自 达哥哥 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/u010413309/article/details/81090905?utm_source=copy

那就是当两个碰撞体重叠在一起时(至于怎么重叠,只要改层就可以了)射线总是返回一个数组,一定要记住这一点,而Onmouse....函数者则总是触发这个数组中的第一个元素。
当两个碰撞体重叠时,unity并不总是调用同一个碰撞体的Onmouse...函数,这也许是很多初学者苦苦不能发现的一点(真是坑):
Onmouse调用的是射线返回的第一个元素,而碰撞体重叠时,射线获取碰撞体的顺序并不一定总是一样的。

最后的处理方式:参考HighlightSystem插件中的选择方式:调用一帧高亮的函数On();

using UnityEngine;

[RequireComponent(typeof(Camera))]
public class HighlightControl : MonoBehaviour {

    public LayerMask targetingLayerMask = -1;//-1代表everything 如果公共属性是一个枚举值,会有选择

    float targetingRayLength = Mathf.Infinity;//射线长度为无穷大

    Camera cam;//不局限于主摄像机

    void Start () {
        cam = GetComponent<Camera>();
	}


    void Update()
    {
        TargetingRayCast();//Update中的代码封装成函数
    }

    public void TargetingRayCast()
    {
        Vector3 mp = Input.mousePosition;

        Transform targetTransform = null;//设置空对象

        if (cam != null)
        {
            RaycastHit hitInfo;

            Ray ray = cam.ScreenPointToRay(new Vector3(mp.x,mp.y,0f));

            if(Physics.Raycast(ray.origin,ray.direction,out hitInfo, targetingRayLength, targetingLayerMask.value))
            {
                targetTransform = hitInfo.collider.transform;
            }
        }

        if (targetTransform != null)
        {
            HighlightableObject ho = targetTransform.root.GetComponentInChildren<HighlightableObject>();
            if (ho != null)
            {                
                ho.On(Color.blue);//这一帧高亮
                if (Input.GetButtonDown("Fire1"))//这个比鼠标适用范围更大
                {
                    ho.ConstantOn(Color.blue);
                    //TODO:选中后做的事情                    
                }                
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_36622009/article/details/82973779