using UnityEngine; using UnityEngine.EventSystems; using System.Runtime.InteropServices; using System.Collections.Generic; using System; //[ExecuteAlways] public class GridSelector : MonoBehaviour { public struct RenderData { public int barrier; //阻隔点,高度值 public float isSelected; public float r; public float g; public float b; } [Space] [Range(0f, 1f)] [Header("调整透明度")] public float gridAlpha = 1; private MeshRenderer mapRenderer; private MeshCollider mapCollider; private Map map; public int horizontalNumber { get { return Mathf.CeilToInt(map.width / map.sideWidth); } } public int verticalNumber { get { return Mathf.CeilToInt(map.height / map.sideHeight); } } public int totalNumber { get { return horizontalNumber * verticalNumber; } } public int moveNum; private ComputeBuffer inputbuffer; public RenderData[] dataArray; public List selectedGridIndex = new List(); private int shiftBeginIndex; private List lassoPos = new List(); private LineRenderer lassoLine; public CellType getCellType(int index) { return (CellType)dataArray[index].barrier; } public CellType CellType { set; get; } public void OnMapCreated(Map map) { this.map = map; moveNum = 0; mapRenderer.material.SetVector("_Size", new Vector4(horizontalNumber, verticalNumber)); mapRenderer.material.SetFloat("_UserInput", 1); inputbuffer = new ComputeBuffer(totalNumber, Marshal.SizeOf(typeof(RenderData))); dataArray = new RenderData[totalNumber]; //创建新的地图默认为全部是可行走区域 for (int i = 0; i < totalNumber; i++) { dataArray[i].barrier = (int)CellType.Move; } RefreshPlaneRender(); } public RenderData[] GetGridData() { return dataArray; } public void setdataArrayIndex(int index,float cellheight, int barrier) { if (index >= dataArray.Length) return; int height = (int)(cellheight * 100); height += 10000; int mask = dataArray[index].barrier & 0xFFFF; //去除之前的8-16位 //mask &= 0xFF; //移除之前的信息值再加新的 mask &= ~(int)CellType.Move; mask &= ~(int)CellType.Obstacle; mask |= barrier; //先取出之前的高度值 dataArray[index].barrier = height << 16; dataArray[index].barrier |= mask; setDataColor(index); } public int getdataByPos(Vector3 pos) { int hitIndex = Mathf.FloorToInt(pos.x / map.sideWidth) + Mathf.FloorToInt(pos.z / map.sideHeight) * horizontalNumber; return hitIndex; } public Vector2Int getMapGrid(Vector3 pos) { return getMapGrid(new Vector2(pos.x,pos.y)); } public Vector2Int getMapGrid(Vector2 pos) { var grid = new Vector2Int(); grid.x = Mathf.FloorToInt(pos.x / map.sideWidth); grid.y = Mathf.FloorToInt(pos.y / map.sideHeight); return grid; } public Vector2 getPosByGrid(Vector2Int grid) { return new Vector2(grid.x * map.sideWidth + map.sideWidth/2, grid.y * map.sideHeight + map.sideHeight / 2); } private void Awake() { mapRenderer = GetComponent(); mapCollider = GetComponent(); GameObject go = GameObject.Instantiate(MapManager.Instance.line.gameObject); go.transform.SetParent(transform); lassoLine = go.GetComponent(); lassoLine.positionCount = 0; lassoLine.startWidth = 0.1f; lassoLine.endWidth = 0.1f; lassoLine.gameObject.SetActive(false); } private void OnDestroy() { if (inputbuffer != null) { inputbuffer.Release(); } } private int GetIndexByXY(int x, int y) { int index = x + y * horizontalNumber; return index; } /// /// 这里采用的算法是每行从左到右的算法,但是过滤了已经重复过的格子 /// ************* /// *****678***** /// *****4*5***** /// *****123***** /// ************* /// /// /// private int FindMapHeight(int index) { GetXyByIndex(index, out int oldx, out int oldy); //像外扩展,找到一个邻近的高度值 int maxR = 1000; int stepI; for (int r = 1; r < maxR; r++) { for (int j = -r; j <= r; j++) { if (j == -r || j == r) { stepI = 1; } else { stepI = r * 2; } for (int i = -r; i <= r; i += stepI) { int x = oldx + i; int y = oldy + j; if (x < 0 || x >= horizontalNumber || y < 0 || y >= verticalNumber) { continue; } int neighborIndex = x + y * horizontalNumber; int neighborValue = dataArray[neighborIndex].barrier; if (neighborValue != 0) { return neighborValue; } } } } return 1; } float lastAlpha = 1; private void Update() { if (lastAlpha != gridAlpha) { map.ChangeGridAlpha(gridAlpha); lastAlpha = gridAlpha; } //先处理移动区域,要先处理之前的区域数据 if (Input.GetKeyDown(KeyCode.C)) { for (int i = 0, length = selectedGridIndex.Count; i < length; i++) { int index = selectedGridIndex[i]; //if ((dataArray[index].barrier & (int)CellType.Obstacle) != 0) //{ // dataArray[index].barrier &= ~(int)CellType.Obstacle; //} //dataArray[index].barrier |= (int)CellType.Move; setDataCellType(index, true); } RefreshPlaneRender(); } if (Input.GetKeyDown(KeyCode.X)) { for (int i = 0, length = selectedGridIndex.Count; i < length; i++) { int index = selectedGridIndex[i]; //if ((dataArray[index].barrier & (int)CellType.Move) != 0) //{ // dataArray[index].barrier &= ~(int)CellType.Move; //} //dataArray[index].barrier |= (int)CellType.Obstacle; setDataCellType(index, false); } RefreshPlaneRender(); } if (Input.GetKeyUp(KeyCode.Z)) { lassoPos.Clear(); lassoLine.gameObject.SetActive(false); lassoLine.positionCount = 0; } if (Input.GetMouseButtonDown(0)) { if (mapCollider.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out RaycastHit hit, float.PositiveInfinity)) { Vector2 hitUv = hit.textureCoord; int hitIndex = Mathf.FloorToInt(hitUv.x * horizontalNumber) + Mathf.FloorToInt(hitUv.y * verticalNumber) * horizontalNumber; if (!Input.GetKey(KeyCode.LeftShift)) { if (Input.GetKey(KeyCode.LeftControl)) { shiftBeginIndex = hitIndex; SetGridIndexSelected(hitIndex, dataArray[hitIndex].isSelected != 1f); RefreshPlaneRender(); } else if (Input.GetKey(KeyCode.Z)) { Vector2 hitPos = GetCenterPosByIndex(hitIndex); if (lassoPos.Count == 0 || lassoPos[0] != hitPos) { if (lassoPos.Count == 0) { SetAllUnselected(); } SetGridIndexSelected(hitIndex, true); lassoLine.gameObject.SetActive(true); lassoLine.positionCount++; lassoLine.SetPosition(lassoLine.positionCount - 1, new Vector3(hitPos.x,transform.position.y + 0.1f, hitPos.y)); lassoPos.Add(hitPos); } else { lassoLine.positionCount++; lassoLine.SetPosition(lassoLine.positionCount - 1, new Vector3(hitPos.x,transform.position.y + 0.1f, hitPos.y)); lassoPos.Add(hitPos); for (int i = 0; i < totalNumber; i++) { Vector2 gridPos = GetCenterPosByIndex(i); bool isSelected = false; for (int j = 0, length = lassoPos.Count - 1; j < length; j++) { Vector2 pos0 = lassoPos[j]; Vector2 pos1 = lassoPos[j + 1]; if (Pnpoly(gridPos, pos0, pos1)) { isSelected = !isSelected; } } SetGridIndexSelected(i, isSelected); } } if (lassoLine.positionCount == 2) { //CSSMoveMgr.Instance.FindPath(lassoPos[0], lassoPos[1]); //在这里寻找路径 } RefreshPlaneRender(); } else if (!Input.GetKey(KeyCode.LeftAlt)) //左alt键涉及到镜头操作,所以屏蔽掉 { shiftBeginIndex = hitIndex; SetAllUnselected(); SetGridIndexSelected(hitIndex, true); RefreshPlaneRender(); } } } else { SetAllUnselected(); RefreshPlaneRender(); } } else if (Input.GetMouseButton(0)) { if (mapCollider.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out RaycastHit hit, float.PositiveInfinity)) { if (Input.GetKey(KeyCode.LeftShift)) { Vector2 hitUv = hit.textureCoord; int hitIndex = Mathf.FloorToInt(hitUv.x * horizontalNumber) + Mathf.FloorToInt(hitUv.y * verticalNumber) * horizontalNumber; int beginX, beginY; GetXyByIndex(shiftBeginIndex, out beginX, out beginY); int hitX, hitY; GetXyByIndex(hitIndex, out hitX, out hitY); beginPos.x = beginX; beginPos.z = beginY; endPos.x = hitX; endPos.z = hitY; //CSSMoveMgr.Instance.FindPath(new Vector3(beginX,0,beginY),new Vector3(hitX,0,hitY)); ShiftKeySelect(hitIndex); RefreshPlaneRender(); } } } } private Vector3 beginPos = new Vector3(); private Vector3 endPos = new Vector3(); private void OnGUI() { GUIStyle style = new GUIStyle() { fontSize = 30 }; style.normal.textColor = Color.red; int width = Screen.width; int height = Screen.height; GUI.Label(new Rect(width - 320, height - 150, 400, 50), "按住Shift按钮多选", style); GUI.Label(new Rect(width - 320, height - 100, 400, 50), "选中后C键取消格子信息", style); GUI.Label(new Rect(width - 320, height - 50, 400, 50), "选中后X键确定格子信息", style); style.normal.textColor = Color.green; if (selectedGridIndex.Count == 0) { return; } else if (selectedGridIndex.Count == 1) { int beginIndex = selectedGridIndex[0]; GetXyByIndex(beginIndex, out int x, out int y); string labelText = string.Format( "所选点XY序列:({0},{1})", x, y); Vector2 labelSize = style.CalcSize(new GUIContent(labelText)); GUI.Label( new Rect(Screen.width - labelSize.x - 20, 20, labelSize.x, labelSize.y), labelText, style ); //GUI.Label(new Rect(width - 820, 20, 400, 50), string.Format("所选点XY序列:({0},{1}) 高度{2} 点类型 {3}", x, y, ((dataArray[beginIndex].barrier >> 16) - 10000)/100.0f, CellTypeColors.GetAreaStr((dataArray[beginIndex].barrier)), style)); } else { int beginIndex = selectedGridIndex[0]; int endIndex = selectedGridIndex[selectedGridIndex.Count - 1]; GetXyByIndex(beginIndex, out int x0, out int y0); GetXyByIndex(endIndex, out int x1, out int y1); GUI.Label(new Rect(width - 420, 20, 400, 50), string.Format("所选起点XY序列:({0},{1})", x0, y0), style); GUI.Label(new Rect(width - 420, 90, 400, 50), string.Format("所选终点XY序列:({0},{1})", x1, y1), style); } } private void SetGridIndexSelected(int index, bool isSelected) { if (isSelected) { if (!selectedGridIndex.Contains(index)) { selectedGridIndex.Add(index); dataArray[index].isSelected = 1f; } } else { selectedGridIndex.Remove(index); dataArray[index].isSelected = 0f; } } private void setDataColor(int index) { Color color = CellTypeColors.GetColor((CellType)dataArray[index].barrier); dataArray[index].r = color.r; dataArray[index].g = color.g; dataArray[index].b = color.b; } private void setDataCellType(int index,bool IsCancel) { if (UICellEditor.Instance == null) return; if (UICellEditor.Instance.editorGrid == CellType.Move || UICellEditor.Instance.editorGrid == CellType.Obstacle) { if (IsCancel) { if ((dataArray[index].barrier & (int)CellType.Obstacle) != 0) { dataArray[index].barrier &= ~(int)CellType.Obstacle; } dataArray[index].barrier |= (int)CellType.Move; } else { if ((dataArray[index].barrier & (int)CellType.Move) != 0) { dataArray[index].barrier &= ~(int)CellType.Move; } dataArray[index].barrier |= (int)CellType.Obstacle; } } else if (UICellEditor.Instance.editorGrid == CellType.Safe) { if (IsCancel) { if ((dataArray[index].barrier & (int)CellType.Safe) != 0) { dataArray[index].barrier &= ~(int)CellType.Safe; } } else { dataArray[index].barrier |= (int)CellType.Safe; } } else if (UICellEditor.Instance.editorGrid == CellType.Stall) { if (IsCancel) { if ((dataArray[index].barrier & (int)CellType.Stall) != 0) { dataArray[index].barrier &= ~(int)CellType.Stall; } } else { dataArray[index].barrier |= (int)CellType.Stall; } } else if (UICellEditor.Instance.editorGrid == CellType.Hide) { if (IsCancel) { if ((dataArray[index].barrier & (int)CellType.Hide) != 0) { dataArray[index].barrier &= ~(int)CellType.Hide; } } else { dataArray[index].barrier |= (int)CellType.Hide; } } } public void FullAllArea() { for (int i = 0; i < dataArray.Length; i++) { CellType cell = (CellType)dataArray[i].barrier; if (cell.HasFlag(CellType.Move)) { dataArray[i].barrier &= ~(int)CellType.Move; } dataArray[i].barrier |= (int)CellType.Obstacle; } RefreshPlaneRender(); } public void ClearSelectArea() { for (int i = 0; i < dataArray.Length; i++) { CellType cell = (CellType)dataArray[i].barrier; if (cell.HasFlag(CellType.Obstacle)) { dataArray[i].barrier &= ~(int)CellType.Obstacle; } dataArray[i].barrier |= (int)CellType.Move; } RefreshPlaneRender(); } public void RefreshPlaneRender() { moveNum = 0; for (int i = 0; i < dataArray.Length; i++) { setDataColor(i); CellType cell = (CellType)dataArray[i].barrier; if (cell.HasFlag(CellType.Move)) { moveNum++; } } inputbuffer.SetData(dataArray); mapRenderer.material.SetBuffer("_InputData", inputbuffer); } public void GetXyByIndex(int index,out int x,out int y) { x = index % horizontalNumber; y = index / horizontalNumber; } //TODO 这里有改动,应该是对的 private Vector2 GetCenterPosByIndex(int index) { GetXyByIndex(index, out int x, out int y); return new Vector2((x + 0.5f)*map.sideWidth, (y + 0.5f) * map.sideHeight); } private bool Pnpoly(Vector2 gridPos, Vector2 pos0, Vector2 pos1) { bool tmp0 = (gridPos.y < pos1.y) != (gridPos.y < pos0.y); bool tmp1 = gridPos.x <= (pos0.x - pos1.x) * (gridPos.y - pos1.y) / (pos0.y - pos1.y) + pos1.x; return tmp0 && tmp1; } private void SetAllUnselected() { for (int i = selectedGridIndex.Count - 1; i >= 0; i--) { SetGridIndexSelected(selectedGridIndex[i], false); } } private void ShiftKeySelect(int hitIndex) { int beginX, beginY; GetXyByIndex(shiftBeginIndex, out beginX, out beginY); int hitX, hitY; GetXyByIndex(hitIndex, out hitX, out hitY); int minX = Mathf.Min(beginX, hitX); int maxX = Mathf.Max(beginX, hitX); int minY = Mathf.Min(beginY, hitY); int maxY = Mathf.Max(beginY, hitY); shiftBeginIndex = hitIndex; for (int y = 0; y < verticalNumber; y++) { for (int x = 0; x < horizontalNumber; x++) { bool isWithin = x >= minX && x <= maxX && y >= minY && y <= maxY; if (isWithin) { int index = x + y * horizontalNumber; SetGridIndexSelected(index, true); } } } } public Vector2Int GetMouseByCell() { Vector2Int cell = new Vector2Int(); if (mapCollider.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out RaycastHit hit, float.PositiveInfinity)) { Vector2 hitUv = hit.textureCoord; cell.x = Mathf.FloorToInt(hitUv.x * horizontalNumber); cell.y = Mathf.FloorToInt(hitUv.y * verticalNumber); } return cell; } public Vector2Int GetMouseByCell(Vector3 mousePositon) { Vector2Int cell = new Vector2Int(); if (mapCollider.Raycast(Camera.main.ScreenPointToRay(mousePositon), out RaycastHit hit, float.PositiveInfinity)) { Vector2 hitUv = hit.textureCoord; cell.x = Mathf.FloorToInt(hitUv.x * horizontalNumber); cell.y = Mathf.FloorToInt(hitUv.y * verticalNumber); } return cell; } }