WolfActGrid.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using Newtonsoft.Json;
  5. /**
  6. 狼的行动区域,为了避免狼的行动目的坐标重合的问题。
  7. */
  8. public class WolfActGrid : MonoBehaviour
  9. {
  10. [SerializeField] TextAsset jsonText;
  11. JsonConfig config;
  12. [System.NonSerialized] public AreaMatrix areaMatrix = new AreaMatrix();
  13. [SerializeField] Material[] sphereMaterials;
  14. public static WolfActGrid ins;
  15. //调试绘制模式-手动开关
  16. bool debugDrawing = false;
  17. //调试-生成新的地域矩阵,不从配置中读取
  18. bool debugNewAreaMatrix = false;
  19. void Awake()
  20. {
  21. ins = this;
  22. areaMatrix.wolfActGrid = this;
  23. config = JsonConfig.Load(jsonText.text);
  24. if (debugNewAreaMatrix) {
  25. createAreaMatrix();
  26. } else {
  27. loadAreaMatrix();
  28. }
  29. }
  30. //从配置中加载地域矩阵(前提是有保存在json配置文件内)
  31. void loadAreaMatrix() {
  32. List<List<Vector3>> posMatrix = areaMatrix.posMatrix = config.GetPosMatrix();
  33. config.SetPosMatrixNull();
  34. for (int r = 0; r < posMatrix.Count; r++) {
  35. for (int c = 0; c < posMatrix[r].Count; c++) {
  36. Vector3 pos = posMatrix[r][c];
  37. DebugDrawSphere(pos, r, c);
  38. }
  39. }
  40. }
  41. //动态创建地域矩阵
  42. void createAreaMatrix() {
  43. float circleRadius = 0.6f;
  44. Vector3 standardPosition = transform.position;
  45. Vector3 standardPointer = transform.forward;
  46. float minAngleY = -14f;
  47. float maxAngleY = 16f;
  48. for (float distance = 11.5f; distance <= 50f; distance += circleRadius * 2) {
  49. List<Vector3> posList = new List<Vector3>();
  50. areaMatrix.posMatrix.Add(posList);
  51. float sinValue = circleRadius / distance;
  52. float deltaAngle = 2f * Mathf.Asin(sinValue) / Mathf.PI * 180f;
  53. for (int col = 0; ; col++) {
  54. float angleY = minAngleY + deltaAngle * col;
  55. if (angleY > maxAngleY) break;
  56. Vector3 pointer = Quaternion.AngleAxis(angleY, Vector3.up) * standardPointer;
  57. Vector3 pointerWithLen = pointer * distance;
  58. Vector3 newPos = standardPosition + pointerWithLen;
  59. #region 射线检测是否被树遮挡
  60. float checkRayDistance = 60f;
  61. Vector3 rayPos = newPos;
  62. Vector3 rayDir = Quaternion.AngleAxis(180, Vector3.up) * pointer;
  63. if (Physics.Raycast(rayPos, rayDir, checkRayDistance, LayerMask.GetMask("Test"))) {
  64. continue;
  65. }
  66. Vector3 pointerWithLen1 = Quaternion.AngleAxis(-deltaAngle / 3f, Vector3.up) * pointerWithLen;
  67. Vector3 rayPos1 = standardPosition + pointerWithLen1;
  68. Vector3 rayDir1 = Quaternion.AngleAxis(180, Vector3.up) * pointerWithLen1;
  69. if (Physics.Raycast(rayPos1, rayDir1, checkRayDistance, LayerMask.GetMask("Test"))) {
  70. continue;
  71. }
  72. Vector3 pointerWithLen2 = Quaternion.AngleAxis(deltaAngle / 3f, Vector3.up) * pointerWithLen;
  73. Vector3 rayPos2 = standardPosition + pointerWithLen2;
  74. Vector3 rayDir2 = Quaternion.AngleAxis(180, Vector3.up) * pointerWithLen2;
  75. if (Physics.Raycast(rayPos2, rayDir2, checkRayDistance, LayerMask.GetMask("Test"))) {
  76. continue;
  77. }
  78. #endregion
  79. posList.Add(newPos);
  80. DebugDrawSphere(newPos, areaMatrix.posMatrix.Count - 1, posList.Count - 1);
  81. }
  82. }
  83. }
  84. void DebugDrawSphere(Vector3 pos, int r, int c) {
  85. if (!debugDrawing) return;
  86. GameObject sphere = transform.Find("Sphere").gameObject;
  87. GameObject o = GameObject.Instantiate(sphere, pos, Quaternion.identity, transform);
  88. o.name = r + "_" + c;
  89. o.SetActive(true);
  90. o.AddComponent<WolfActGridCell>().pos = pos;
  91. }
  92. public void DebugOccupySphere(string name, bool occupy) {
  93. if (!debugDrawing) return;
  94. transform.Find(name).GetComponent<MeshRenderer>().material = occupy ? sphereMaterials[1] : sphereMaterials[0];
  95. }
  96. //提供给狼的接口,扑击结束后,跑回的地点
  97. int runBackPointIndex = -1;
  98. public Vector3 GetRunBackPointAfterPounce() {
  99. if (runBackPointIndex == -1) runBackPointIndex = Random.Range(0, 2);
  100. runBackPointIndex++;
  101. return this.transform.Find("RunBackPoint" + (runBackPointIndex % 2)).position;
  102. }
  103. public class AreaMatrix {
  104. public List<List<Vector3>> posMatrix = new List<List<Vector3>>();
  105. //格式:"行_列"
  106. public Dictionary<object, string> occupyDC = new Dictionary<object, string>();
  107. public WolfActGrid wolfActGrid;
  108. //计算水平距离
  109. float calDis(Vector3 p1, Vector3 p2) {
  110. return Mathf.Sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.z - p2.z) * (p1.z - p2.z));
  111. }
  112. // 占用距离最近的格子,如果最近的被占用则广度优先寻找附近较近的格子
  113. public bool occupyPos(Vector3 p, object obj) {
  114. float minDis = float.MaxValue;
  115. int bestR = 0;
  116. int bestC = 0;
  117. for (int r = 0; r < posMatrix.Count; r++) {
  118. for (int c = 0; c < posMatrix[r].Count; c++) {
  119. Vector3 pos = posMatrix[r][c];
  120. float dis = calDis(pos, p);
  121. if (dis < minDis) {
  122. minDis = dis;
  123. bestR = r;
  124. bestC = c;
  125. }
  126. }
  127. }
  128. object cur_occupy_obj = checkOccupy(bestR, bestC);
  129. //如果目标格子被其它对象占用,则过渡优先寻找附近的格子,因为矩阵是扇形,目前的fbs有偏差,但无妨
  130. if (cur_occupy_obj != null && !obj.Equals(cur_occupy_obj)) {
  131. int sr = bestR;
  132. int sc = bestC;
  133. List<string> openList = new List<string>();
  134. openList.Add(sr + "_" + sc);
  135. int scanIndex = 1;
  136. bool breakBFS = false;
  137. while (true) {
  138. int i = 0;
  139. while (i < 8) {
  140. i++;
  141. if (i == 1) { sc++; }
  142. if (i == 2) { sr--; }
  143. if (i == 3) { sc--; }
  144. if (i == 4) { sc--; }
  145. if (i == 5) { sr++; }
  146. if (i == 6) { sr++; }
  147. if (i == 7) { sc++; }
  148. if (i == 8) { sc++; }
  149. if (sr >= 0 && sr < posMatrix.Count && sc >= 0 && sc < posMatrix[sr].Count) {
  150. string keyName = sr + "_" + sc;
  151. if (!openList.Contains(keyName)) {
  152. object now_occupy_obj = checkOccupy(sr, sc);
  153. if (now_occupy_obj == null || obj.Equals(now_occupy_obj)) {
  154. bestR = sr;
  155. bestC = sc;
  156. breakBFS = true;
  157. break;
  158. }
  159. //加入
  160. openList.Add(keyName);
  161. }
  162. }
  163. }
  164. if (breakBFS) break;
  165. if (scanIndex < openList.Count) {
  166. string[] str = openList[scanIndex].Split('_');
  167. scanIndex++;
  168. sr = int.Parse(str[0]);
  169. sc = int.Parse(str[1]);
  170. } else {
  171. return false;
  172. }
  173. }
  174. }
  175. //找到最佳的格子
  176. Vector3 bestPoint = posMatrix[bestR][bestC];
  177. p.x = bestPoint.x;
  178. p.z = bestPoint.z;
  179. //释放自己以前占用的格子
  180. releaseOccupy(obj);
  181. //占用目标格子
  182. Occupy(bestR, bestC, obj);
  183. return true;
  184. }
  185. public object checkOccupy(int r, int c) {
  186. string keyName = r + "_" + c;
  187. foreach (var item in occupyDC)
  188. {
  189. if (item.Value.Equals(keyName)) return item.Key;
  190. }
  191. return null;
  192. }
  193. public void releaseOccupy(object obj) {
  194. string keyName = null;
  195. occupyDC.TryGetValue(obj, out keyName);
  196. if (keyName == null) {
  197. return;
  198. }
  199. occupyDC.Remove(obj);
  200. wolfActGrid.DebugOccupySphere(keyName, false);
  201. }
  202. public void Occupy(int r, int c, object obj) {
  203. string keyName = r + "_" + c;
  204. occupyDC[obj] = keyName;
  205. wolfActGrid.DebugOccupySphere(keyName, true);
  206. if (!wolfActGrid.debugDrawing) return;
  207. if (obj.GetType().Equals(typeof(Wolf))) {
  208. Wolf wolf = (Wolf) obj;
  209. WolfLineRender wolfLineRender = wolf.GetComponentInChildren<WolfLineRender>();
  210. if (!wolfLineRender) {
  211. GameObject prefab = wolfActGrid.transform.Find("WolfLineRender").gameObject;
  212. GameObject o = GameObject.Instantiate(prefab, wolf.transform.position + Vector3.up * 0.8f, Quaternion.identity, wolf.transform);
  213. wolfLineRender = o.GetComponent<WolfLineRender>();
  214. o.SetActive(true);
  215. }
  216. wolfLineRender.SetDestination(posMatrix[r][c]);
  217. }
  218. }
  219. }
  220. class JsonConfig {
  221. public string posMatrix = null;
  222. //清空,避免占用内存
  223. public void SetPosMatrixNull() {
  224. posMatrix = null;
  225. }
  226. public List<List<Vector3>> GetPosMatrix() {
  227. string[] lines = posMatrix.Split('\n');
  228. List<List<Vector3>> list = new List<List<Vector3>>();
  229. foreach (var line in lines)
  230. {
  231. if (line.Trim().Length == 0) continue;
  232. string[] vectorStrs = line.Split(' ');
  233. List<Vector3> childList = new List<Vector3>();
  234. foreach (var vectorStr in vectorStrs)
  235. {
  236. string[] valStrs = vectorStr.Split('_');
  237. Vector3 vec = new Vector3(
  238. float.Parse(valStrs[0]),
  239. float.Parse(valStrs[1]),
  240. float.Parse(valStrs[2])
  241. );
  242. childList.Add(vec);
  243. }
  244. list.Add(childList);
  245. }
  246. return list;
  247. }
  248. public void SetPosMatrix(List<List<Vector3>> list) {
  249. posMatrix = "";
  250. for (int i = 0; i < list.Count; i++) {
  251. for (int j = 0; j < list[i].Count; j++) {
  252. Vector3 pos = list[i][j];
  253. posMatrix += pos.x + "_" + pos.y + "_" + pos.z;
  254. if (j < list[i].Count - 1) posMatrix += " ";
  255. }
  256. if (i < list.Count - 1) posMatrix += "\n";
  257. };
  258. }
  259. public void Write() {
  260. string filePath =
  261. "E:\\UnityProject\\SmartBow\\Assets\\BowArrow\\Scripts\\GameChallenge\\WoldActGird\\WolfActGrid.json";
  262. if (!System.IO.File.Exists(filePath)) {
  263. Debug.LogError("JsonConfig-File-NotExist");
  264. return;
  265. }
  266. try
  267. {
  268. System.IO.StreamWriter writer = new System.IO.StreamWriter(filePath);
  269. writer.Write(JsonConvert.SerializeObject(this));
  270. writer.Close();
  271. }
  272. catch (System.Exception e)
  273. {
  274. Debug.LogError("JsonConfig-Write-Fail");
  275. Debug.LogError(e.Message);
  276. }
  277. }
  278. public static JsonConfig Load(string jsonText) {
  279. JsonConfig jsonConfig = JsonConvert.DeserializeObject<JsonConfig>(jsonText);
  280. if (jsonConfig == null) jsonConfig = new JsonConfig();
  281. return jsonConfig;
  282. }
  283. }
  284. [ContextMenu("SaveJsonConfig")]
  285. void SaveJsonConfig() {
  286. config.SetPosMatrix(areaMatrix.posMatrix);
  287. config.Write();
  288. Debug.LogWarning("网格配置保存成功");
  289. }
  290. }