Unity中用鼠标拖拽框选3D物体的效果

项目中需要一个用鼠标框选物体的功能,类似星际或红警那种拖拽鼠标框选小兵的方式。参考了网上一些方法,但是有瑕疵或是运行不正确。所以自己花时间做了一个,一如既往的不是太监代码100%有用。

使用方法:
1.创建一个名为Marquee的C#脚本,并将代码全部复制过去
2.挂载到场景的一个空物体上
3.将摄像机拖到mainCamera字段中
4.新建一个Image并拖到marquee字段中
5.新建一个空物体并命名为SelectObjs 并将所有能选中的物体放到这个空物体下(为方便测试观察所有待选中物体的材质可以先保持默认材质)
6.运行

如果能帮到你的话,非常高兴。

using UnityEngine;
using UnityEngine.UI;

public class Marquee : MonoBehaviour
{
    [Tooltip("OnGUI调试")]
    public bool onGUIDebug;
    public Camera mainCamera;
    public Image marquee;
    public MeshRenderer[] objs;
    private Vector2 startPos, nowPos;
    private Rect selectRect = new Rect();
    private Vector2 center;
    private Vector2 size;
    private Vector2 leftTop = new Vector2(0, 1);
    private Vector2 rightTop = new Vector2(1, 1);
    private Vector2 leftBottom = new Vector2(0, 0);
    private Vector2 rightBottom = new Vector2(1, 0);
    private Vector2 absVector2;
    private RectTransform broderRectTransform;


    void Start()
    {
        broderRectTransform = marquee.rectTransform;
        objs = GameObject.Find("SelectObjs").GetComponentsInChildren<MeshRenderer>();
        marquee.gameObject.SetActive(false);

        for (int i = 0; i < objs.Length; i++) objs[i].material.color = Color.white;
    }

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            startPos = Vector2.zero;
            nowPos = Vector2.zero;
            center = Vector2.zero;

            marquee.gameObject.SetActive(true);
            startPos = Input.mousePosition;
        }

        if (Input.GetMouseButton(0))
        {
            nowPos = Input.mousePosition;

            if (center == Vector2.zero)
                center = (startPos + nowPos) * 0.5f;

         
            if (nowPos.x > startPos.x && nowPos.y < startPos.y)
            {
                broderRectTransform.pivot = leftTop;
                size = new Vector2(Mathf.Abs((nowPos.x - startPos.x)), Mathf.Abs((nowPos.y - startPos.y)));
            }

          
            if (nowPos.x < startPos.x && nowPos.y < startPos.y)
            {
                broderRectTransform.pivot = rightTop;
                size = new Vector2(Mathf.Abs((nowPos.x - startPos.x)) * -1, Mathf.Abs((nowPos.y - startPos.y)));
            }

         
            if (nowPos.x > startPos.x && nowPos.y > startPos.y)
            {
                broderRectTransform.pivot = leftBottom;
                size = new Vector2(Mathf.Abs((nowPos.x - startPos.x)), Mathf.Abs((nowPos.y - startPos.y)) * -1);
            }

        
            if (nowPos.x < startPos.x && nowPos.y > startPos.y)
            {
                broderRectTransform.pivot = rightBottom;
                size = new Vector2(Mathf.Abs((nowPos.x - startPos.x)) * -1, Mathf.Abs((nowPos.y - startPos.y)) * -1);
            }

            absVector2.x = Mathf.Abs(size.x);
            absVector2.y = Mathf.Abs(size.y);

            SetBroder(center, absVector2);

            selectRect.x = center.x;
            selectRect.y = Screen.height - center.y;
            selectRect.width = size.x;
            selectRect.height = size.y;

            SelectObj(JudgeRect(selectRect));
        }

        if (Input.GetMouseButtonUp(0))
        {
            marquee.gameObject.SetActive(false);
            size = Vector3.zero;

            for (int i = 0; i < objs.Length; i++)
                objs[i].material.color = Color.white;
        }
    }


    private void SelectObj(Rect selectRect)
    {
        for (int i = 0; i < objs.Length; i++)
        {
            Vector3 temp = mainCamera.WorldToScreenPoint(objs[i].transform.position);
            temp.y = Screen.height - temp.y;

            if (selectRect.Contains(temp)) objs[i].material.color = Color.yellow;

            else objs[i].material.color = Color.white;
        }
    }

    private Rect JudgeRect(Rect baseRect)
    {
        Rect result = default;

        if (baseRect.width > 0 && baseRect.height > 0)
        {
            result = baseRect;
        }

        if (baseRect.width < 0 && baseRect.height > 0)
        {
            result = new Rect(baseRect.x - Mathf.Abs(baseRect.width), baseRect.y, Mathf.Abs(baseRect.width), Mathf.Abs(baseRect.height));
        }

        if (baseRect.width > 0 && baseRect.height < 0)
        {
            result = new Rect(baseRect.x, baseRect.y - Mathf.Abs(baseRect.height), Mathf.Abs(baseRect.width), Mathf.Abs(baseRect.height));
        }

        if (baseRect.width < 0 && baseRect.height < 0)
        {
            result = new Rect(baseRect.x - Mathf.Abs(baseRect.width), baseRect.y - Mathf.Abs(baseRect.height), Mathf.Abs(baseRect.width), Mathf.Abs(baseRect.height));
        }

        return result;
    }


    private void SetBroder(Vector2 pos, Vector2 size)
    {
        marquee.gameObject.SetActive(true);
        marquee.rectTransform.position = pos;
        marquee.rectTransform.sizeDelta = size;
    }

    public void OnGUI()
    {
        if (onGUIDebug == true)
        {
            Rect myRect = JudgeRect(selectRect);
            GUI.Box(myRect, "这是一个矩形区域");
        }
    }
}
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值