项目中需要一个用鼠标框选物体的功能,类似星际或红警那种拖拽鼠标框选小兵的方式。参考了网上一些方法,但是有瑕疵或是运行不正确。所以自己花时间做了一个,一如既往的不是太监代码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, "这是一个矩形区域");
}
}
}