Game视图选择Scene物体

【前言】

之前做很多项目的时候,在画面中突然出现的物体想要去选取调试,基本上都只能在scene去找,或者直接选择相机物体,在相机视野里双击物体查找,直到最近,在做一个项目时需要选择视野里的地砖查看视图,就想了却一下多年的心愿,写了这个插件。

在这里插入图片描述
配图:game视图选取地砖

【思路分析】

由于是Game视图选择物体,所以Game视图一般有两种选取方式:
一、使用射线检测碰撞体,也就意味着场景的物体身上必须有合适的碰撞体,然后根据检测信息知道物体选择物体。
二、UGUI有事件系统可以知道鼠标是否在UI上,这个接口或者EventTrigger需要勾选RaycastTarget,所以就猜想是否是射线检测,为此也写射线调试了下勾选了RaycastTarget的UI,好像是行不通,又或者是UI底层的射线和我们平时用的射线有所区别,由于UI没碰撞体的,所以可能是由屏幕位置来知道是否在UI上吧,反正我没看过UGUI源码不得而知。

综上所述,我们选择了第一种方式实现,这样的话索要选择的物体必须加碰撞体,如果场景中加碰撞体麻烦,建议在预制体加比较快。

【进入开发环节】

在开发过程中,我发现暂停后Update等生命周期函数会停止,于是乎我意识到,假设一个怪物在Game视图中突然出现很快消失,那么很不利于选择到该怪物,所以只能暂停停止生命周期,选择怪物,于是我舍弃了Update,改用了EditorApplication.update来替代Update相关功能,在暂停模式,这个方法便代替了Update执行动态选取。

1.Start方法生成Sphere(代替鼠标方便查看),再生成一个Sphere用于显示高亮效果,然后最最最重要的一点就是注册EditorApplication.update事件

private void Start()
    {
    
    
        print("Start");
        mousePoint = GameObject.CreatePrimitive(PrimitiveType.Sphere).GetComponent<Transform>();
        DestroyImmediate(mousePoint.GetComponent<Collider>());
        mousePoint.localScale = Vector3.one * 0.1f;

        // 用于边缘效果展示的物体
        highLightObj = GameObject.CreatePrimitive(PrimitiveType.Sphere).GetComponent<Transform>(); print("highLightObj=" + highLightObj);
        DestroyImmediate(highLightObj.GetComponent<Collider>());
        highLightObj.GetComponent<MeshRenderer>().material = Resources.Load<Material>("MT_Silhouette");
        highLightObj.gameObject.SetActive(false);

        //EditorApplication.update += Update0;
    }

引用文本

2.Update0里面动态做射线检测,用于比对前后帧的物体来更换材质球,来显示到描边效果,最后在鼠标左键单击,来定位到选择的物体上。

    void Update0()
    {
    
    
        print("update");
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit raycastHit = new RaycastHit();
        if (Physics.Raycast(ray, out raycastHit))
        {
    
    
            //print(!nowObj);
            if (!nowObj || nowObj.name != raycastHit.transform.name)//把上次检测到的物体和新检测的raycastHit的物体名比对,如果不是上一次的物体进入逻辑
            {
    
    
                if (nowObj)
                {
    
    
                    // 换回原来的材质
                    nowObj.GetComponent<MeshRenderer>().material = oldMaterial;
                }
                // 射线当前检测到的物体
                nowObj = raycastHit.transform.gameObject;
                // 更换材质球
                oldMaterial = raycastHit.transform.GetComponent<MeshRenderer>().sharedMaterial;
                nowObj.GetComponent<MeshRenderer>().material = Resources.Load<Material>("MT_HighLinght");
                // 显示选中效果
                highLightObj.position = raycastHit.transform.position;
                highLightObj.rotation = raycastHit.transform.rotation;
                highLightObj.localScale = raycastHit.transform.localScale;
                highLightObj.GetComponent<MeshFilter>().mesh = raycastHit.collider.GetComponent<MeshFilter>().sharedMesh;
                highLightObj.gameObject.SetActive(true);

                print(nowObj);
            }
            if (Input.GetMouseButtonDown(0))
            {
    
    
                if (nowObj != null)
                {
    
    
                    Selection.activeGameObject = nowObj;
                    SceneView.lastActiveSceneView.FrameSelected();
                }
            }
        }
        else
        {
    
    
            //print("射线未射到");
            if (highLightObj.gameObject.activeSelf)
            {
    
    
                //print("highLightObj处于激活");
                // 隐藏选中效果
                highLightObj.gameObject.SetActive(false);
                // 换回原来的材质
                nowObj.GetComponent<MeshRenderer>().material = oldMaterial;
                // 置空射线检测到的物体
                nowObj = null;
            }
        }
        Debug.DrawRay(Camera.main.transform.position, GetMousePositionOnWorld() - Camera.main.transform.position, Color.red);
        mousePoint.position = GetMousePositionOnWorld();
    }
    
   Vector3 GetMousePositionOnWorld()
    {
    
    
        Vector3 mousePos = Input.mousePosition;
        // Z 值不能为零,Z 值为零该方法返回值为相机的世界坐标
        // 鼠标坐标值转换为世界坐标时,该方法返回值的 Z  值为:相机的 Z 值加上下面一行代码的赋值
        // 例如:相机 Z 值为-10,经过下面一行代码赋值后,该方法返回值的 Z 值为 0 
        mousePos.z = 10;
        return Camera.main.ScreenToWorldPoint(mousePos);
    }

【最后想说】

底下有源码资源包,起初,我想过没有运行前也能从Game视图选择物体,虽然EditorApplication.update支持刷新,但是射线的相关功能好像在主线程中才能使用(运行unity后),所以没有运行选取没有想到更好的解决方案,如果有更好的意见,可以留言我,评论我都会一一查看的。

案例源码下载:Game视图选择物体unitypackage

猜你喜欢

转载自blog.csdn.net/qq_42541751/article/details/113870969
今日推荐