using UnityEngine; using System.Collections.Generic; using UnityEditor; using System.IO; using UnityEngine.AI; using System; public class NavMeshExport : EditorWindow { static byte[] _writedBytes = null; /** 字节写入位置索引 */ static int _writeIndex = 128; private static int[][] m_Datas; // 主文件 private static List> m_MainData = null; [MenuItem("美术工具/场景/合并布怪区")] static void Init() { var _window = CreateInstance(); _window.Show(); } private void BuildCurData() { float _navWidth; float _navHeight; float _maxWidth; float _maxHeight; Vector3[] _navVertices = NavMesh.CalculateTriangulation().vertices; if (_navVertices == null || _navVertices.Length <= 0) { return; } List _chkList = new List(_navVertices); _chkList.Sort((Vector3 v1, Vector3 v2) => { return v1.x > v2.x ? -1 : 1; }); _navWidth = _chkList[0].x - _chkList[_chkList.Count - 1].x; _maxWidth = _navWidth + _chkList[_chkList.Count - 1].x; _chkList.Sort((Vector3 v1, Vector3 v2) => { return v1.z > v2.z ? -1 : 1; }); _navHeight = _chkList[0].z - _chkList[_chkList.Count - 1].z; _maxHeight = _navHeight + _chkList[_chkList.Count - 1].z; float _outWidth = (int)(_maxWidth * 2) + 1; float _outHeight = (int)(_maxHeight * 2) + 1; float _column; float _row; var _curData = new List>(); for (int r = 0; r < _outHeight; ++r) { List _rowData = new List(); for (int c = 0; c < _outWidth; ++c) { _column = c * .5f; _row = r * .5f; if (IsInNavmeshArea(_column, _row)) { _rowData.Add(00); } else { _rowData.Add(03); } } _curData.Add(_rowData); } MapCollide _file = new MapCollide(); _file.width = _curData[0].Count; _file.height = _curData.Count; _file.data = new int[_curData.Count][]; for (int r = 0; r < _curData.Count; ++r) { _file.data[r] = new int[_curData[r].Count]; for (int c = 0; c < _curData[r].Count; ++c) { _file.data[r][c] = _curData[r][c]; } } LitJson.JsonData _jsonData = LitJson.JsonMapper.ToJson(_file); string _dirPath = Application.dataPath + "/Editor/MapCollideFiles/"; if (!Directory.Exists(_dirPath)) { Directory.CreateDirectory(_dirPath); } string _filePath = _dirPath + UnityEngine.SceneManagement.SceneManager.GetActiveScene().name + ".json"; using (StreamWriter _sw = new StreamWriter(_filePath)) { _sw.Write(_jsonData.ToString()); } AssetDatabase.Refresh(); } private void CombineFromFile() { string _inputPath = EditorUtility.OpenFilePanel("打开合并文件", Application.dataPath + "/Editor/MapCollideFiles/", "asset"); if (string.IsNullOrEmpty(_inputPath)) { return; } string _fileName = Path.GetFileNameWithoutExtension(_inputPath); string _configPath = "Assets/Editor/MapCollideFiles/" + _fileName + ".asset"; MapCombine _config = AssetDatabase.LoadAssetAtPath(_configPath); if (_config == null) { Debug.LogErrorFormat("{0} 文件无法读取.", _configPath); return; } string _mainFilePath = Application.dataPath + "/Editor/MapCollideFiles/" + _config.mainFileName + ".json"; string _jsonData = string.Empty; using (StreamReader _sr = new StreamReader(_mainFilePath)) { _jsonData = _sr.ReadToEnd(); } if (string.IsNullOrEmpty(_jsonData)) { Debug.LogErrorFormat("{0} 文件无法读取.", _config.mainFileName); return; } MapCollide _file = LitJson.JsonMapper.ToObject(_jsonData); if (m_MainData == null) { m_MainData = new List>(); } else { m_MainData.Clear(); } for (int i = 0; i < _file.height; ++i) { List _row = new List(); for (int j = 0; j < _file.width; ++j) { _row.Add(_file.data[i][j]); } m_MainData.Add(_row); } for (int i = 0; i < _config.dataList.Count; ++i) { Combine(_config.dataList[i]); } _writedBytes = null; string _exportPath = EditorUtility.SaveFilePanel("", "", _config.mainFileName, "col"); if (string.IsNullOrEmpty(_exportPath)) { return; } if (File.Exists(_exportPath)) { File.Delete(_exportPath); } WriteBytes(BitConverter.GetBytes((uint)(m_MainData[0].Count))); WriteBytes(BitConverter.GetBytes((uint)(m_MainData.Count))); m_Datas = new int[m_MainData.Count][]; for (int i = 0; i < m_Datas.Length; ++i) { m_Datas[i] = new int[m_MainData[i].Count]; } for (int r = 0; r < m_MainData.Count; ++r) { for (int c = 0; c < m_MainData[r].Count; ++c) { m_Datas[r][c] = m_MainData[r][c]; } } for (int i = 0; i < m_Datas.Length; i++) { WriteBytes(m_Datas[i]); } WriteToFile(_exportPath); } private Vector3 m_ChkPos; private void OnGUI() { if (GUILayout.Button("合并配置文件地图")) { CombineFromFile(); } if (GUILayout.Button("生成当前地图的合并文件")) { BuildCurData(); } GUILayout.Space(10); EditorGUILayout.BeginHorizontal(); m_ChkPos = EditorGUILayout.Vector3Field("测试点", m_ChkPos); if (GUILayout.Button("测试")) { if (IsInNavmeshArea(m_ChkPos.x, m_ChkPos.z)) { Debug.Log("正常点..........."); } else { Debug.Log("障碍点..........."); } } EditorGUILayout.EndHorizontal(); if (GUILayout.Button("直接导出当前地图.col文件")) { Export(); } if (m_Datas == null) { return; } Rect _rect = new Rect(0, 0, 2, 2); for (int i = 0; i < m_Datas.Length; ++i) { if (m_Datas[i] == null) { continue; } for (int j = 0; j < m_Datas[i].Length; ++j) { if (m_Datas[i][j] == 00) { GUI.color = Color.green; } else if (m_Datas[i][j] == 03) { GUI.color = Color.red; } _rect.position = new Vector2(j * 2 + 4, i * 2 + 72); GUI.Box(_rect, ""); } } } private void OnDisable() { m_Datas = null; m_MainData = null; } private void Combine(MapCombine.MapCombineInfo info) { if (m_MainData == null) { return; } // 读取文件 string _filePath = Application.dataPath + "/Editor/MapCollideFiles/" + info.fileName + ".json"; string _jsonData = string.Empty; using (StreamReader _sr = new StreamReader(_filePath)) { _jsonData = _sr.ReadToEnd(); } if (string.IsNullOrEmpty(_jsonData)) { Debug.LogErrorFormat("{0} 文件无法读取.", info.fileName); return; } MapCollide _file = LitJson.JsonMapper.ToObject(_jsonData); int _prevRowCount = m_MainData.Count; int _prevColumnCount = m_MainData[0].Count; int _curRowCount = _file.height; int _curColumnCount = _file.width; int _newRowCount = 0; int _newColumnCount = 0; // 填入的偏移R + 新地图的高度 与 之前地图的高度进行对比, 得到差值 int _deltaRowCount = info.offsetY + _curRowCount - _prevRowCount; // 差值大于0, 则新建一个数组, 此数组为旧的R + 差值 if (_deltaRowCount > 0) { _newRowCount = _prevRowCount + _deltaRowCount; } else { _newRowCount = _prevRowCount; } // 列同理 int _deltaColumnCount = info.offsetX + _curColumnCount - _prevColumnCount; if (_deltaColumnCount > 0) { _newColumnCount = _prevColumnCount + _deltaColumnCount; } else { _newColumnCount = _prevColumnCount; } // 扩容 for (int i = m_MainData.Count; i < _newRowCount; ++i) { List _tmp = new List(); for (int j = 0; j < _prevColumnCount; ++j) { _tmp.Add(03); } m_MainData.Add(_tmp); } for (int i = 0; i < m_MainData.Count; ++i) { for (int j = _prevColumnCount; j < _newColumnCount; ++j) { m_MainData[i].Add(03); } } // 赋值 for (int i = 0; i < _file.data.Length; ++i) { for (int j = 0; j < _file.data[i].Length; ++j) { m_MainData[i + info.offsetY][j + info.offsetX] = _file.data[i][j]; } } } static void Export() { string path = EditorUtility.SaveFilePanel("", "", UnityEngine.SceneManagement.SceneManager.GetActiveScene().name, "col"); if (string.IsNullOrEmpty(path)) { return; } if (File.Exists(path)) { File.Delete(path); } float _navWidth; float _navHeight; float _maxWidth; float _maxHeight; Vector3[] _navVertices = NavMesh.CalculateTriangulation().vertices; if (_navVertices == null || _navVertices.Length <= 0) { return; } List _chkList = new List(_navVertices); _chkList.Sort((Vector3 v1, Vector3 v2) => { return v1.x > v2.x ? -1 : 1; }); _navWidth = _chkList[0].x - _chkList[_chkList.Count - 1].x; _maxWidth = _navWidth + _chkList[_chkList.Count - 1].x; _chkList.Sort((Vector3 v1, Vector3 v2) => { return v1.z > v2.z ? -1 : 1; }); _navHeight = _chkList[0].z - _chkList[_chkList.Count - 1].z; _maxHeight = _navHeight + _chkList[_chkList.Count - 1].z; int _outWidth = (int)(_maxWidth * 2) + 1; int _outHeight = (int)(_maxHeight * 2) + 1; WriteBytes(BitConverter.GetBytes((uint)(_outWidth))); WriteBytes(BitConverter.GetBytes((uint)(_outHeight))); Debug.LogFormat("地图宽度: {0}, 地图高度: {1}", _outWidth, _outHeight); float _column; float _row; int[][] _datas = new int[_outHeight][]; for (int i = 0; i < _datas.Length; i++) { _datas[i] = new int[_outWidth]; } //System.Text.StringBuilder _sb1 = new System.Text.StringBuilder(); for (int r = 0; r < _outHeight; ++r) { for (int c = 0; c < _outWidth; ++c) { _column = c * .5f; _row = r * .5f; if (IsInNavmeshArea(_column, _row)) { _datas[r][c] = 00; //_sb1.Append("0"); } else { _datas[r][c] = 03; //_sb1.Append("#"); } } //_sb1.Append("\r\n"); } //using (StreamWriter _writer = new StreamWriter(Application.dataPath + "/aaa.txt")) //{ // _writer.Write(_sb1.ToString()); //} for (int i = 0; i < _datas.Length; i++) { WriteBytes(_datas[i]); } WriteToFile(path); } private static bool IsInNavmeshArea(float column, float row) { int _mask = 1 << LayerMask.NameToLayer("Navmesh"); return Physics.Raycast(new Vector3(column, 100, row), Vector3.down, 200, _mask) || Physics.Raycast(new Vector3(column + .5f, 100, row), Vector3.down, 200, _mask) || Physics.Raycast(new Vector3(column, 100, row + .5f), Vector3.down, 200, _mask) || Physics.Raycast(new Vector3(column + .5f, 100, row + .5f), Vector3.down, 200, _mask); } private static void WriteToFile(string path) { FileStream fs = File.Open(path, FileMode.CreateNew, FileAccess.ReadWrite); BinaryWriter bw = new BinaryWriter(fs); //将byte数组写入文件中 bw.Write(_writedBytes, 0, _writedBytes.Length); bw.Flush(); bw.Close(); fs.Dispose(); fs.Close(); _writeIndex = 128; _writedBytes = null; } /// /// 写入一段字节数据 /// /// private static void WriteBytes(byte[] vBytes) { Array.Resize(ref _writedBytes, _writeIndex + vBytes.Length); vBytes.CopyTo(_writedBytes, _writeIndex); _writeIndex = _writedBytes.Length; } /// /// 转整型数值数组为字节 /// /// /// private static void WriteBytes(int[] vInts) { int l = vInts.Length; byte[] vRst; int i; vRst = new byte[l]; for (i = 0; i < l; i++) { Array.Copy(BitConverter.GetBytes((byte)vInts[i]), 0, vRst, i, 1); } WriteBytes(vRst); } }