最近在看RTS游戏视频注意到了选框功能,就尝试做了一下

unity inspector 自定义复选框 unity选择物体_ide

功能实现

unity inspector 自定义复选框 unity选择物体_List_02

脚本挂载到Camera上,要不然OnPostRender()函数无法调用,rectMat新建一个材质球,设置成默认的Sprites就可以了

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;

public class Test选框 : MonoBehaviour
{
    MeshRenderer mesh;
    List<GameObject> characters;
    List<MeshRenderer> charactersMesh;
   
    Color initialcolor;
    Transform cubes;
    public  Color rectColor;

    private Vector3 start = Vector3.zero;//记下鼠标按下位置

    // private Material rectMat = null;//画线的材质 不设定系统会用当前材质画线 结果不可控
    public Material rectMat=null; //这里使用Sprite下的defaultshader的材质即可

    private bool drawRectangle = false;//是否开始画线标志

    Material material;//替换的材质
    Material initialmaterial;
    // Use this for initialization

    void Start()
    {
       
        cubes = transform.Find("/Cubes");
        Debug.Log(cubes.childCount);

        material = new Material(Shader.Find("Custom/CubeMiaoBian"));
       
        characters = new List<GameObject>();
        charactersMesh = new List<MeshRenderer>();
        initialcolor = cubes.GetChild(1).GetComponent<MeshRenderer>().material.color;
       
       
        for (int i = 0; i < cubes.childCount; i++)
        {
            characters.Add(cubes.GetChild(i).gameObject);
            charactersMesh.Add(cubes.GetChild(i).GetComponent<MeshRenderer>());
            
        }
      
        rectMat.hideFlags = HideFlags.HideAndDontSave;

        rectMat.shader.hideFlags = HideFlags.HideAndDontSave;
        //不显示在hierarchy面板中的组合,不保存到场景并且卸载Resources.UnloadUnusedAssets不卸载的对象。

    }


    void Update()
    {
       
        if (Input.GetMouseButtonDown(0))
        {
            ResetCube();

            drawRectangle = true;//如果鼠标左键按下 设置开始画线标志

            start = Input.mousePosition;//记录按下位置

        }
        else if (Input.GetMouseButtonUp(0))
        {

            drawRectangle = false;//如果鼠标左键放开 结束画线
            checkSelection(start, Input.mousePosition);
        }

    }

    

   void OnPostRender()
    {//画线这种操作推荐在OnPostRender()里进行 而不是直接放在Update,所以需要标志来开启
        if (drawRectangle)
        {
            Debug.Log("................");
            Vector3 end = Input.mousePosition;//鼠标当前位置
            GL.PushMatrix();//保存摄像机变换矩阵,把投影视图矩阵和模型视图矩阵压入堆栈保存

            if (!rectMat)
               
                return;

            rectMat.SetPass(0);//为渲染激活给定的pass。

            GL.LoadPixelMatrix();//设置用屏幕坐标绘图

            GL.Begin(GL.QUADS);//开始绘制矩形

            GL.Color(new Color(rectColor.r, rectColor.g, rectColor.b, 0.1f));
            //设置颜色和透明度,方框内部透明

            //绘制顶点
            GL.Vertex3(start.x, start.y, 0);

            GL.Vertex3(end.x, start.y, 0);

            GL.Vertex3(end.x, end.y, 0);

            GL.Vertex3(start.x, end.y, 0);

            GL.End();


            GL.Begin(GL.LINES);//开始绘制线
            
            GL.Color(rectColor);//设置方框的边框颜色 边框不透明

            GL.Vertex3(start.x, start.y, 0);

            GL.Vertex3(end.x, start.y, 0);

            GL.Vertex3(end.x, start.y, 0);

            GL.Vertex3(end.x, end.y, 0);

            GL.Vertex3(end.x, end.y, 0);

            GL.Vertex3(start.x, end.y, 0);

            GL.Vertex3(start.x, end.y, 0);

            GL.Vertex3(start.x, start.y, 0);

            GL.End();

            GL.PopMatrix();//恢复摄像机投影矩阵

        }

    }

    void ResetCube()
    {
        foreach (var cube in charactersMesh)
        {
            cube.material = initialmaterial;
            cube.material.color = initialcolor;
        }
        
        
    }
    //检测被选择的物体
    void checkSelection(Vector3 start, Vector3 end)
    {

        Vector3 p1 = Vector3.zero;

        Vector3 p2 = Vector3.zero;

        if (start.x > end.x)
        {//这些判断是用来确保p1的xy坐标小于p2的xy坐标,因为画的框不见得就是左下到右上这个方向的

            p1.x = end.x;

            p2.x = start.x;

        }

        else
        {

            p1.x = start.x;

            p2.x = end.x;

        }

        if (start.y > end.y)
        {

            p1.y = end.y;

            p2.y = start.y;

        }

        else
        {

            p1.y = start.y;

            p2.y = end.y;

        }

        foreach (GameObject obj in characters)
        {//把可选择的对象保存在characters数组里

            
            Vector3 location = Camera.main.WorldToScreenPoint(obj.transform.position);//把对象的position转换成屏幕坐标

            if (location.x < p1.x || location.x > p2.x || location.y < p1.y || location.y > p2.y

            || location.z < Camera.main.nearClipPlane || location.z > Camera.main.farClipPlane)//z方向就用摄像机的设定值,看不见的也不需要选择了

            {
                //disselecting(obj);//上面的条件是筛选 不在选择范围内的对象,然后进行取消选择操作,比如把物体放到default层,就不显示轮廓线了
            }

            else

            {
                obj.GetComponent<Renderer>().material = material;

                obj.GetComponent<Renderer>().material.color = Color.red;
                //selecting(obj);//否则就进行选中操作,比如把物体放到画轮廓线的层去

            }

        }

    }
}

Cube描边,Shader代码,过几天再研究下人物描边

Shader "Custom/CubeMiaoBian"
{
    Properties
    {
		_Color("Color", color) = (1,1,1,1)
		_Width("Width", range(0,0.5)) = 0.1
    }
    SubShader
    {
		Tags { "Queue"="Transparent" }
		Pass {

  //如果要显示背面的线框,取消下面两个注释即可
			//cull off
			//ZWrite off
			blend srcalpha oneminussrcalpha
			CGPROGRAM

			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"
			uniform sampler2D _MainTex;
			uniform float4 _MainTex_ST;
			fixed4 _Color;
			fixed _Width;

			struct a2v {
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
			};

			struct v2f {
				float4 pos : SV_POSITION;
				float2 uv : TEXCOORD0;
			};

			v2f vert(a2v v) {
				v2f o;

				o.pos = UnityObjectToClipPos(v.vertex);
				o.uv = v.uv;

				return o;
			}

			float4 frag(v2f i) : SV_Target {

				fixed4 col = fixed4(0,0,0,0);//Cube的基础颜色
				
				col += saturate(step(i.uv.x, _Width) + step(1 - _Width, i.uv.x) + step(i.uv.y, _Width) + step(1 - _Width, i.uv.y)) * _Color;

				return  col;
			}

			ENDCG
		}
    }
}