RTSManhattan.cs 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using CommonAI.RTS;
  5. using CommonLang.Vector;
  6. using CommonLang;
  7. using CommonLang.Concurrent;
  8. using CommonAI.ZoneServer.JSGModule;
  9. namespace CommonAI.RTS.Manhattan
  10. {
  11. /// <summary>
  12. /// 实现了曼哈顿算法的A*寻路算法
  13. /// </summary>
  14. public partial class AstarManhattan : RTSAstar<AstarManhattan.MMapNode>
  15. {
  16. #region _Fields_
  17. private MTerrain terrain_map;
  18. private IManhattanMap manhattan_map;
  19. private MSpaceAStar space_div;
  20. private readonly float space_sqrt;
  21. private readonly float cellw;
  22. private readonly float cellh;
  23. private readonly float cell_sqrt;
  24. private readonly float totalw;
  25. private readonly float totalh;
  26. private int area_count = 0;
  27. private readonly int div_size;
  28. private int space_optmize_limit_distance = 4;
  29. private int space_div_enable_distance = 4;
  30. private DirtyNodes<MMapNode> dirty_nodes = new DirtyNodes<MMapNode>();
  31. #endregion
  32. //---------------------------------------------------------------------------------------------------------------------
  33. /// <summary>
  34. /// 创建一个以曼哈顿算法的A*寻路算法
  35. /// </summary>
  36. /// <param name="map_data">地图适配器</param>
  37. /// <param name="inclined">是否要检测斜边可以移动</param>
  38. /// <param name="space_size">空间切割尺寸</param>
  39. public AstarManhattan(int uniqueID, IManhattanMap map_data, bool inclined = true, int space_size = 0)
  40. {
  41. //21.3, 7.3, 5.7, 3
  42. this.manhattan_map = map_data;
  43. this.cellw = map_data.CellW;
  44. this.cellh = map_data.CellH;
  45. this.totalw = cellw * map_data.XCount;
  46. this.totalh = cellh * map_data.YCount;
  47. if (totalw < ushort.MinValue || totalw > ushort.MaxValue || totalh < ushort.MinValue || totalh > ushort.MaxValue)
  48. {
  49. throw new Exception(string.Format("Terrain Size must in ({0}~{1}", ushort.MinValue, ushort.MaxValue));
  50. }
  51. this.div_size = space_size;
  52. this.cell_sqrt = (float)Math.Sqrt((cellw * cellw) + (cellh * cellh));
  53. this.space_sqrt = (float)Math.Sqrt((div_size * div_size) + (div_size * div_size));
  54. this.terrain_map = new MTerrain(this, map_data, inclined);
  55. base.Init(terrain_map);
  56. this.ResetArea();
  57. if (space_size > 0)
  58. {
  59. //this.space_div = MSpaceNodeCache.GetCacheAStart(uniqueID, this, space_size);
  60. this.space_div = new MSpaceAStar(uniqueID, this, space_size);
  61. }
  62. }
  63. protected override void Disposing()
  64. {
  65. base.Disposing();
  66. if (space_div != null)
  67. {
  68. space_div.Dispose();
  69. space_div = null;
  70. }
  71. this.dirty_nodes.Clear();
  72. this.manhattan_map = null;
  73. this.terrain_map = null;
  74. }
  75. //---------------------------------------------------------------------------------------------------------------------
  76. #region _Properties_
  77. public IManhattanMap MMap { get { return manhattan_map; } }
  78. /// <summary>
  79. /// 超过多少格子(空间分割格子)不进行路径优化
  80. /// </summary>
  81. public int SpaceOptimizePathLimitDistance
  82. {
  83. get { return space_optmize_limit_distance; }
  84. set { if (value > 1) { space_optmize_limit_distance = value; } }
  85. }
  86. /// <summary>
  87. /// 超过多少格子(空间分割格子)启用空间分割
  88. /// </summary>
  89. public int SpaceDivEnableDistance
  90. {
  91. get { return space_div_enable_distance; }
  92. set { if (value > 1) { space_div_enable_distance = value; } }
  93. }
  94. /// <summary>
  95. /// 空间分割尺度
  96. /// </summary>
  97. public int SpaceDivSize
  98. {
  99. get { return div_size; }
  100. }
  101. /// <summary>
  102. /// 空间分割寻路
  103. /// </summary>
  104. public MSpaceAStar SpaceAstar
  105. {
  106. get { return space_div; }
  107. }
  108. /// <summary>
  109. /// 是否支持8方向
  110. /// </summary>
  111. public bool IsInclined
  112. {
  113. get { return terrain_map.is_inclined; }
  114. }
  115. /// <summary>
  116. /// 地图总共多少可行走区域
  117. /// </summary>
  118. public int AreaCount
  119. {
  120. get { return area_count; }
  121. }
  122. #endregion
  123. //---------------------------------------------------------------------------------------------------------------------
  124. #region _ForEachTerrain_
  125. public static void NormalizeTerrainRegionByBlock(IManhattanMap tmap, ref int min_x, ref int min_y, ref int max_x, ref int max_y)
  126. {
  127. min_x = Math.Max(min_x, 0);
  128. min_y = Math.Max(min_y, 0);
  129. max_x = Math.Min(max_x, tmap.XCount - 1);
  130. max_y = Math.Min(max_y, tmap.YCount - 1);
  131. }
  132. /// <summary>
  133. ///
  134. /// </summary>
  135. /// <param name="bx"></param>
  136. /// <param name="by"></param>
  137. public delegate void ForEachTerrainAction(int bx, int by);
  138. public static void ForEachTerrainPoint(IManhattanMap tmap, float sx, float sy, ForEachTerrainAction action)
  139. {
  140. int cx1 = (int)((sx) / tmap.CellW);
  141. int cy1 = (int)((sy) / tmap.CellH);
  142. if (cx1 >= 0 && cx1 < tmap.XCount && cy1 >= 0 && cy1 < tmap.YCount)
  143. {
  144. action(cx1, cy1);
  145. }
  146. }
  147. public static void ForEachTerrainRect(IManhattanMap tmap, float sx, float sy, float w, float h, ForEachTerrainAction action)
  148. {
  149. int cx1 = (int)((sx) / tmap.CellW);
  150. int cy1 = (int)((sy) / tmap.CellH);
  151. int cx2 = (int)((sx + w) / tmap.CellW);
  152. int cy2 = (int)((sy + h) / tmap.CellH);
  153. cx1 = Math.Max(cx1, 0);
  154. cy1 = Math.Max(cy1, 0);
  155. cx2 = Math.Min(cx2, tmap.XCount - 1);
  156. cy2 = Math.Min(cy2, tmap.YCount - 1);
  157. for (int cx = cx1; cx <= cx2; ++cx)
  158. {
  159. for (int cy = cy1; cy <= cy2; ++cy)
  160. {
  161. action(cx, cy);
  162. }
  163. }
  164. }
  165. public static void ForEachTerrainRound(IManhattanMap tmap, float sx, float sy, float r, ForEachTerrainAction action)
  166. {
  167. int cx1 = (int)((sx - r) / tmap.CellW);
  168. int cy1 = (int)((sy - r) / tmap.CellH);
  169. int cx2 = (int)((sx + r) / tmap.CellW);
  170. int cy2 = (int)((sy + r) / tmap.CellH);
  171. cx1 = Math.Max(cx1, 0);
  172. cy1 = Math.Max(cy1, 0);
  173. cx2 = Math.Min(cx2, tmap.XCount - 1);
  174. cy2 = Math.Min(cy2, tmap.YCount - 1);
  175. for (int cx = cx1; cx <= cx2; ++cx)
  176. {
  177. for (int cy = cy1; cy <= cy2; ++cy)
  178. {
  179. if (CMath.intersectRectRound(
  180. cx * tmap.CellW,
  181. cy * tmap.CellH,
  182. cx * tmap.CellW + tmap.CellW,
  183. cy * tmap.CellH + tmap.CellH,
  184. sx, sy, r))
  185. {
  186. action(cx, cy);
  187. }
  188. }
  189. }
  190. }
  191. public static void ForEachTerrainEllipse(IManhattanMap tmap, float sx, float sy, float w, float h, ForEachTerrainAction action)
  192. {
  193. float scrw = w / 2;
  194. float scrh = h / 2;
  195. float scx = sx + w / 2;
  196. float scy = sy + h / 2;
  197. int cx1 = (int)((sx) / tmap.CellW);
  198. int cy1 = (int)((sy) / tmap.CellH);
  199. int cx2 = (int)((sx + w) / tmap.CellW);
  200. int cy2 = (int)((sy + h) / tmap.CellH);
  201. cx1 = Math.Max(cx1, 0);
  202. cy1 = Math.Max(cy1, 0);
  203. cx2 = Math.Min(cx2, tmap.XCount - 1);
  204. cy2 = Math.Min(cy2, tmap.YCount - 1);
  205. float cx0;
  206. float cy0;
  207. for (int cx = cx1; cx <= cx2; ++cx)
  208. {
  209. for (int cy = cy1; cy <= cy2; ++cy)
  210. {
  211. cx0 = cx * tmap.CellW;
  212. cy0 = cy * tmap.CellH;
  213. if (CMath.intersectRectEllipse(cx0, cy0, cx0 + tmap.CellW, cy0 + tmap.CellH, scx, scy, scrw, scrh))
  214. {
  215. action(cx, cy);
  216. }
  217. }
  218. }
  219. }
  220. public static void ForEachTerrainLine(IManhattanMap tmap, float x0, float y0, float x1, float y1, ForEachTerrainAction action)
  221. {
  222. int bx0 = (int)(x0 / tmap.CellW);
  223. int by0 = (int)(y0 / tmap.CellH);
  224. int bx1 = (int)(x1 / tmap.CellW);
  225. int by1 = (int)(y1 / tmap.CellH);
  226. if (bx0 > bx1) CUtils.Swap(ref bx0, ref bx1);
  227. if (by0 > by1) CUtils.Swap(ref by0, ref by1);
  228. if (bx0 < 0) bx0 = 0;
  229. if (by0 < 0) by0 = 0;
  230. if (bx1 >= tmap.XCount) bx1 = tmap.XCount - 1;
  231. if (by1 >= tmap.YCount) by1 = tmap.YCount - 1;
  232. float cx0;
  233. float cy0;
  234. for (int by = by0; by <= by1; by++)
  235. {
  236. for (int bx = bx0; bx <= bx1; bx++)
  237. {
  238. cx0 = bx * tmap.CellW;
  239. cy0 = by * tmap.CellH;
  240. if (CMath.intersectRectLine(cx0, cy0, cx0 + tmap.CellW, cy0 + tmap.CellH, x0, y0, x1, y1))
  241. {
  242. action(bx, by);
  243. }
  244. }
  245. }
  246. }
  247. public static void ForEachTerrainStripWidth(IManhattanMap tmap, float x0, float y0, float x1, float y1, float line_r, ForEachTerrainAction action)
  248. {
  249. CommonLang.Geometry.Vector2[] points = CMath.toStripWidthPolygon(x0, y0, x1, y1, line_r);
  250. CommonLang.Geometry.Vector2 min, max;
  251. CMath.toBoundingBox(points, out min, out max);
  252. int bx0 = (int)(min.X / tmap.CellW);
  253. int by0 = (int)(min.Y / tmap.CellH);
  254. int bx1 = (int)(max.X / tmap.CellW);
  255. int by1 = (int)(max.Y / tmap.CellH);
  256. if (bx0 < 0) bx0 = 0;
  257. if (by0 < 0) by0 = 0;
  258. if (bx1 >= tmap.XCount) bx1 = tmap.XCount - 1;
  259. if (by1 >= tmap.YCount) by1 = tmap.YCount - 1;
  260. float cx0;
  261. float cy0;
  262. for (int by = by0; by <= by1; by++)
  263. {
  264. for (int bx = bx0; bx <= bx1; bx++)
  265. {
  266. cx0 = bx * tmap.CellW;
  267. cy0 = by * tmap.CellH;
  268. if (CMath.intersectRectPolygon(cx0, cy0, cx0 + tmap.CellW, cy0 + tmap.CellH, points))
  269. {
  270. action(bx, by);
  271. }
  272. }
  273. }
  274. }
  275. /// <summary>
  276. ///
  277. /// </summary>
  278. /// <param name="bx"></param>
  279. /// <param name="by"></param>
  280. /// <returns>True can break</returns>
  281. public delegate bool ForEachTerrainPredicate(int bx, int by);
  282. public static bool ForEachTerrainPoint(IManhattanMap tmap, float sx, float sy, ForEachTerrainPredicate action)
  283. {
  284. int cx1 = (int)((sx) / tmap.CellW);
  285. int cy1 = (int)((sy) / tmap.CellH);
  286. if (cx1 >= 0 && cx1 < tmap.XCount && cy1 >= 0 && cy1 < tmap.YCount)
  287. {
  288. if (action(cx1, cy1))
  289. {
  290. return true;
  291. }
  292. }
  293. return false;
  294. }
  295. public static bool ForEachTerrainRect(IManhattanMap tmap, float sx, float sy, float w, float h, ForEachTerrainPredicate action)
  296. {
  297. int cx1 = (int)((sx) / tmap.CellW);
  298. int cy1 = (int)((sy) / tmap.CellH);
  299. int cx2 = (int)((sx + w) / tmap.CellW);
  300. int cy2 = (int)((sy + h) / tmap.CellH);
  301. cx1 = Math.Max(cx1, 0);
  302. cy1 = Math.Max(cy1, 0);
  303. cx2 = Math.Min(cx2, tmap.XCount - 1);
  304. cy2 = Math.Min(cy2, tmap.YCount - 1);
  305. for (int cx = cx1; cx <= cx2; ++cx)
  306. {
  307. for (int cy = cy1; cy <= cy2; ++cy)
  308. {
  309. if (action(cx, cy))
  310. {
  311. return true;
  312. }
  313. }
  314. }
  315. return false;
  316. }
  317. public static bool ForEachTerrainRound(IManhattanMap tmap, float sx, float sy, float r, ForEachTerrainPredicate action)
  318. {
  319. int cx1 = (int)((sx - r) / tmap.CellW);
  320. int cy1 = (int)((sy - r) / tmap.CellH);
  321. int cx2 = (int)((sx + r) / tmap.CellW);
  322. int cy2 = (int)((sy + r) / tmap.CellH);
  323. cx1 = Math.Max(cx1, 0);
  324. cy1 = Math.Max(cy1, 0);
  325. cx2 = Math.Min(cx2, tmap.XCount - 1);
  326. cy2 = Math.Min(cy2, tmap.YCount - 1);
  327. for (int cx = cx1; cx <= cx2; ++cx)
  328. {
  329. for (int cy = cy1; cy <= cy2; ++cy)
  330. {
  331. if (CMath.intersectRectRound(
  332. cx * tmap.CellW,
  333. cy * tmap.CellH,
  334. cx * tmap.CellW + tmap.CellW,
  335. cy * tmap.CellH + tmap.CellH,
  336. sx, sy, r))
  337. {
  338. if (action(cx, cy))
  339. {
  340. return true;
  341. }
  342. }
  343. }
  344. }
  345. return false;
  346. }
  347. public static bool ForEachTerrainEllipse(IManhattanMap tmap, float sx, float sy, float w, float h, ForEachTerrainPredicate action)
  348. {
  349. float scrw = w / 2;
  350. float scrh = h / 2;
  351. float scx = sx + w / 2;
  352. float scy = sy + h / 2;
  353. int cx1 = (int)((sx) / tmap.CellW);
  354. int cy1 = (int)((sy) / tmap.CellH);
  355. int cx2 = (int)((sx + w) / tmap.CellW);
  356. int cy2 = (int)((sy + h) / tmap.CellH);
  357. cx1 = Math.Max(cx1, 0);
  358. cy1 = Math.Max(cy1, 0);
  359. cx2 = Math.Min(cx2, tmap.XCount - 1);
  360. cy2 = Math.Min(cy2, tmap.YCount - 1);
  361. float cx0;
  362. float cy0;
  363. for (int cx = cx1; cx <= cx2; ++cx)
  364. {
  365. for (int cy = cy1; cy <= cy2; ++cy)
  366. {
  367. cx0 = cx * tmap.CellW;
  368. cy0 = cy * tmap.CellH;
  369. if (CMath.intersectRectEllipse(cx0, cy0, cx0 + tmap.CellW, cy0 + tmap.CellH, scx, scy, scrw, scrh))
  370. {
  371. if (action(cx, cy))
  372. {
  373. return true;
  374. }
  375. }
  376. }
  377. }
  378. return false;
  379. }
  380. public static bool ForEachTerrainLine(IManhattanMap tmap, float x0, float y0, float x1, float y1, ForEachTerrainPredicate action)
  381. {
  382. int bx0 = (int)(x0 / tmap.CellW);
  383. int by0 = (int)(y0 / tmap.CellH);
  384. int bx1 = (int)(x1 / tmap.CellW);
  385. int by1 = (int)(y1 / tmap.CellH);
  386. if (bx0 > bx1) CUtils.Swap(ref bx0, ref bx1);
  387. if (by0 > by1) CUtils.Swap(ref by0, ref by1);
  388. if (bx0 < 0) bx0 = 0;
  389. if (by0 < 0) by0 = 0;
  390. if (bx1 >= tmap.XCount) bx1 = tmap.XCount - 1;
  391. if (by1 >= tmap.YCount) by1 = tmap.YCount - 1;
  392. float cx0;
  393. float cy0;
  394. for (int by = by0; by <= by1; by++)
  395. {
  396. for (int bx = bx0; bx <= bx1; bx++)
  397. {
  398. cx0 = bx * tmap.CellW;
  399. cy0 = by * tmap.CellH;
  400. if (CMath.intersectRectLine(cx0, cy0, cx0 + tmap.CellW, cy0 + tmap.CellH, x0, y0, x1, y1))
  401. {
  402. if (action(bx, by))
  403. {
  404. return true;
  405. }
  406. }
  407. }
  408. }
  409. return false;
  410. }
  411. public static bool ForEachTerrainStripWidth(IManhattanMap tmap, float x0, float y0, float x1, float y1, float line_r, ForEachTerrainPredicate action)
  412. {
  413. CommonLang.Geometry.Vector2[] points = CMath.toStripWidthPolygon(x0, y0, x1, y1, line_r);
  414. CommonLang.Geometry.Vector2 min, max;
  415. CMath.toBoundingBox(points, out min, out max);
  416. int bx0 = (int)(min.X / tmap.CellW);
  417. int by0 = (int)(min.Y / tmap.CellH);
  418. int bx1 = (int)(max.X / tmap.CellW);
  419. int by1 = (int)(max.Y / tmap.CellH);
  420. if (bx0 < 0) bx0 = 0;
  421. if (by0 < 0) by0 = 0;
  422. if (bx1 >= tmap.XCount) bx1 = tmap.XCount - 1;
  423. if (by1 >= tmap.YCount) by1 = tmap.YCount - 1;
  424. float cx0;
  425. float cy0;
  426. for (int by = by0; by <= by1; by++)
  427. {
  428. for (int bx = bx0; bx <= bx1; bx++)
  429. {
  430. cx0 = bx * tmap.CellW;
  431. cy0 = by * tmap.CellH;
  432. if (CMath.intersectRectPolygon(cx0, cy0, cx0 + tmap.CellW, cy0 + tmap.CellH, points))
  433. {
  434. if (action(bx, by))
  435. {
  436. return true;
  437. }
  438. }
  439. }
  440. }
  441. return false;
  442. }
  443. #endregion
  444. //---------------------------------------------------------------------------------------------------------------------
  445. #region _FillTerrain_
  446. public bool TryFillTerrain(int bx, int by, int value)
  447. {
  448. if (manhattan_map.SetValue(bx, by, value))
  449. {
  450. var mnode = terrain_map.getMapNode(bx, by);
  451. if (mnode != null && mnode.resetValue(this.terrain_map))
  452. {
  453. dirty_nodes.AddDirty(mnode);
  454. return true;
  455. }
  456. }
  457. return false;
  458. }
  459. //---------------------------------------------------------------------------------------------------------------------
  460. public void FillTerrain(float sx, float sy, int value)
  461. {
  462. ForEachTerrainPoint(manhattan_map, sx, sy, (bx, by) =>
  463. {
  464. TryFillTerrain(bx, by, value);
  465. });
  466. this.BeginFindPath();
  467. }
  468. public void FillTerrain(float sx, float sy, float w, float h, int value)
  469. {
  470. ForEachTerrainRect(manhattan_map, sx, sy, w, h, (bx, by) =>
  471. {
  472. TryFillTerrain(bx, by, value);
  473. });
  474. this.BeginFindPath();
  475. }
  476. public void FillTerrain(float sx, float sy, float w, float h, int[,] matrix)
  477. {
  478. ForEachTerrainRect(manhattan_map, sx, sy, w, h, (bx, by) =>
  479. {
  480. TryFillTerrain(bx, by, matrix[bx, by]);
  481. });
  482. this.BeginFindPath();
  483. }
  484. //---------------------------------------------------------------------------------------------------------------------
  485. public void FillTerrainByBlock(int bx, int by, int value)
  486. {
  487. if (bx >= 0 && bx < manhattan_map.XCount && by >= 0 && by < manhattan_map.YCount)
  488. {
  489. TryFillTerrain(bx, by, value);
  490. }
  491. this.BeginFindPath();
  492. }
  493. public void FillTerrainByBlock(int bx, int by, int bw, int bh, int value)
  494. {
  495. int cx1 = Math.Max(bx, 0);
  496. int cy1 = Math.Max(by, 0);
  497. int cx2 = Math.Min(bx + bw, manhattan_map.XCount);
  498. int cy2 = Math.Min(by + bh, manhattan_map.YCount);
  499. for (int cx = cx1; cx < cx2; ++cx)
  500. {
  501. for (int cy = cy1; cy < cy2; ++cy)
  502. {
  503. TryFillTerrain(cx, cy, value);
  504. }
  505. }
  506. this.BeginFindPath();
  507. }
  508. public void FillTerrainByBlock(int bx, int by, int bw, int bh, int[,] matrix)
  509. {
  510. int cx1 = Math.Max(bx, 0);
  511. int cy1 = Math.Max(by, 0);
  512. int cx2 = Math.Min(bx + bw, manhattan_map.XCount);
  513. int cy2 = Math.Min(by + bh, manhattan_map.YCount);
  514. for (int cx = cx1; cx < cx2; ++cx)
  515. {
  516. for (int cy = cy1; cy < cy2; ++cy)
  517. {
  518. TryFillTerrain(cx, cy, matrix[cx, cy]);
  519. }
  520. }
  521. this.BeginFindPath();
  522. }
  523. //---------------------------------------------------------------------------------------------------------------------
  524. public void BeginFindPath()
  525. {
  526. if (dirty_nodes.Count > 0)
  527. {
  528. using (var list = ListObjectPool<MMapNode>.AllocAutoRelease(dirty_nodes.Values))
  529. {
  530. var near_table = GetNearTables(IsInclined);
  531. foreach (var dn in list)
  532. {
  533. foreach (var offset in near_table)
  534. {
  535. var sn = GetMapNode(dn.BX + offset[0], dn.BY + offset[1]);
  536. if (sn != null)
  537. {
  538. dirty_nodes.AddDirty(sn);
  539. }
  540. }
  541. }
  542. }
  543. using (var list = ListObjectPool<MMapNode>.AllocAutoRelease(dirty_nodes.Values))
  544. {
  545. foreach (var mn in list)
  546. {
  547. mn.resetNextNodes(this.terrain_map);
  548. }
  549. }
  550. dirty_nodes.Clear();
  551. this.ResetArea();
  552. }
  553. if (space_div != null)
  554. {
  555. this.space_div.beginFindPath();
  556. }
  557. }
  558. /// <summary>
  559. /// 计算连续区域
  560. /// </summary>
  561. private void ResetArea()
  562. {
  563. byte area_index = 0;
  564. HashMap<MMapNode, bool> dirty_map = new HashMap<MMapNode, bool>(terrain_map.TotalNodeCount);
  565. for (int by = 0; by < terrain_map.ycount; by++)
  566. {
  567. for (int bx = 0; bx < terrain_map.xcount; bx++)
  568. {
  569. var mnode = terrain_map.getMapNode(bx, by);
  570. if (mnode != null)
  571. {
  572. mnode.area = 0;
  573. if (!mnode.Blocked)
  574. {
  575. dirty_map.Add(mnode, true);
  576. }
  577. }
  578. }
  579. }
  580. Stack<MMapNode> stack = new Stack<MMapNode>(dirty_map.Count);
  581. while (dirty_map.Count > 0)
  582. {
  583. area_index++;
  584. var exist = dirty_map.GetEnumerator();
  585. stack.Clear();
  586. if (exist.MoveNext())
  587. {
  588. var current = exist.Current.Key;
  589. dirty_map.Remove(current);
  590. stack.Push(current);
  591. }
  592. while (stack.Count > 0)
  593. {
  594. MMapNode cur = stack.Pop();
  595. cur.area = area_index;
  596. for (int i = cur.nextnodes.Length - 1; i >= 0; --i)
  597. {
  598. MMapNode next = cur.nextnodes[i];
  599. if (dirty_map.Remove(next))
  600. {
  601. stack.Push(next);
  602. }
  603. }
  604. }
  605. }
  606. area_count = area_index;
  607. }
  608. #endregion
  609. //---------------------------------------------------------------------------------------------------------------------
  610. #region _FindPath_
  611. public override WayPoint GenWayPoint(MapNode node)
  612. {
  613. return new MWayPoint(node as MMapNode);
  614. }
  615. public enum FindPathResult : byte
  616. {
  617. /// <summary>
  618. /// 可通过
  619. /// </summary>
  620. Cross = 0,
  621. /// <summary>
  622. /// 没有路径
  623. /// </summary>
  624. NoWay = 1,
  625. /// <summary>
  626. /// 原地
  627. /// </summary>
  628. Destination = 2,
  629. /// <summary>
  630. /// 寻路范围超出地图范围
  631. /// </summary>
  632. OutOfMap = 3,
  633. }
  634. public virtual FindPathResult findPath(float sx, float sy, float dx, float dy, out MWayPoint ret, bool optimize = true)
  635. {
  636. ret = null;
  637. int sbx = (int)(sx / cellw);
  638. int sby = (int)(sy / cellh);
  639. int dbx = (int)(dx / cellw);
  640. int dby = (int)(dy / cellh);
  641. if (sbx >= 0 && sbx < terrain_map.xcount &&
  642. sby >= 0 && sby < terrain_map.ycount &&
  643. dbx >= 0 && dbx < terrain_map.xcount &&
  644. dby >= 0 && dby < terrain_map.ycount)
  645. {
  646. if (sbx == dbx && sby == dby)
  647. {
  648. var dn = terrain_map.getMapNode(sbx, sby);
  649. if (dn != null)
  650. {
  651. ret = new MWayPoint(dn);
  652. ret.SetPos(dx, dy);
  653. return FindPathResult.Destination;
  654. }
  655. else
  656. {
  657. return FindPathResult.NoWay;
  658. }
  659. }
  660. var snode = terrain_map.getMapNode(sbx, sby);
  661. var dnode = terrain_map.getMapNode(dbx, dby);
  662. if (snode == null || dnode == null)
  663. {
  664. return FindPathResult.NoWay;
  665. }
  666. if (snode.Blocked || dnode.Blocked)
  667. {
  668. return FindPathResult.NoWay;
  669. }
  670. if (snode.AreaValue != dnode.AreaValue)
  671. {
  672. return FindPathResult.NoWay;
  673. }
  674. BeginFindPath();
  675. #region space_div
  676. if (space_div != null)
  677. {
  678. var sn = space_div.getSpaceNodeByBlock(sbx, sby);
  679. var dn = space_div.getSpaceNodeByBlock(dbx, dby);
  680. if (sn != null && dn != null && sn != dn)
  681. {
  682. if ((Math.Abs(sn.CX - dn.CX) >= space_div_enable_distance) ||
  683. (Math.Abs(sn.CY - dn.CY) >= space_div_enable_distance))
  684. {
  685. if (sn.AnchorNode != null && dn.AnchorNode != null)
  686. {
  687. var space_wp = space_div.findPath(sn, dn) as MSpaceAStar.MSpaceWayPoint;
  688. if (space_wp == null || space_wp.next == null)
  689. {
  690. return FindPathResult.NoWay;
  691. }
  692. space_wp = space_wp.Next;
  693. space_wp.tail.prev.LinkNext(null);
  694. var node_head = space_wp.SpaceNode.AnchorNode;
  695. var node_tail = space_wp.Tail.SpaceNode.AnchorNode;
  696. var path_head = findPathInternal(sx, sy, node_head.PosX, node_head.PosY, snode, node_head, optimize) as MWayPoint;
  697. if (path_head == null)
  698. {
  699. return FindPathResult.NoWay;
  700. }
  701. var path_tail = findPathInternal(node_tail.PosX, node_tail.PosY, dx, dy, node_tail, dnode, optimize) as MWayPoint;
  702. if (path_tail == null)
  703. {
  704. return FindPathResult.NoWay;
  705. }
  706. var path_body = space_wp.ToLinkWayPoint();
  707. if (path_body != null)
  708. {
  709. path_head.tail.LinkNext(path_body);
  710. path_body.tail.LinkNext(path_tail);
  711. if (optimize)
  712. {
  713. if (Math.Abs(sn.CX - dn.CX) <= space_optmize_limit_distance &&
  714. Math.Abs(sn.CY - dn.CY) <= space_optmize_limit_distance)
  715. {
  716. optimizePathInner(path_head);
  717. }
  718. }
  719. }
  720. else
  721. {
  722. path_head.tail.LinkNext(path_tail);
  723. if (optimize)
  724. {
  725. optimizePathInner(path_head);
  726. }
  727. }
  728. ret = path_head;
  729. ret = ret.Next;
  730. return FindPathResult.Cross;
  731. }
  732. }
  733. }
  734. }
  735. #endregion
  736. ret = findPathInternal(sx, sy, dx, dy, snode, dnode, optimize);
  737. if (ret == null || ret.Next == null)
  738. {
  739. return FindPathResult.NoWay;
  740. }
  741. else
  742. {
  743. ret = ret.Next;
  744. return FindPathResult.Cross;
  745. }
  746. }
  747. else
  748. {
  749. return FindPathResult.OutOfMap;
  750. }
  751. }
  752. protected virtual MWayPoint findPathInternal(float sx, float sy, float dx, float dy, MMapNode snode, MMapNode dnode, bool optimize)
  753. {
  754. MWayPoint ret = base.findPath(snode.tempNode, dnode.tempNode) as MWayPoint;
  755. if (ret.next == null)
  756. {
  757. return ret.next as MWayPoint;
  758. }
  759. else
  760. {
  761. MWayPoint root = ret;
  762. MWayPoint tail = root.Tail;
  763. if (!terrain_map.is_inclined)
  764. {
  765. root.SetPos(sx, sy);
  766. tail.SetPos(dx, dy);
  767. }
  768. else
  769. {
  770. var nroot = GenWayPoint(snode);
  771. nroot.LinkNext(root);
  772. root = nroot as MWayPoint;
  773. root.SetPos(sx, sy);
  774. var ntail = GenWayPoint(dnode);
  775. tail.LinkNext(ntail);
  776. tail = ntail as MWayPoint;
  777. tail.SetPos(dx, dy);
  778. }
  779. if (optimize)
  780. {
  781. optimizePathInner(root);
  782. }
  783. ret = root;
  784. }
  785. return ret;
  786. }
  787. protected MWayPoint findPathInternal(MMapNode snode, MMapNode dnode)
  788. {
  789. MWayPoint ret = base.findPath(snode.tempNode, dnode.tempNode) as MWayPoint;
  790. if (ret.next == null)
  791. {
  792. return ret.next as MWayPoint;
  793. }
  794. else
  795. {
  796. optimizePathInner(ret);
  797. }
  798. return ret;
  799. }
  800. protected virtual void optimizePathInner(MWayPoint root)
  801. {
  802. bool finded = false;
  803. do
  804. {
  805. finded = false;
  806. MWayPoint current = root;
  807. while (current != null && current.next != null)
  808. {
  809. MWayPoint next = current.Next;
  810. while (true)
  811. {
  812. if (next == null)
  813. {
  814. current = next;
  815. break;
  816. }
  817. if ((current.PosX == next.PosX) && (current.PosY == next.PosY))
  818. {
  819. current.LinkNext(next.Next);
  820. next = next.Next;
  821. finded = true;
  822. continue;
  823. }
  824. if (next.Next == null)
  825. {
  826. current = next;
  827. break;
  828. }
  829. if (current.IsCenter && next.IsCenter && next.Next.IsCenter)
  830. {
  831. //三点一线//
  832. if (current.BX == next.BX && current.BX == next.Next.BX)
  833. {
  834. current.LinkNext(next.Next);
  835. next = next.Next;
  836. finded = true;
  837. break;
  838. }
  839. if (current.BY == next.BY && current.BY == next.Next.BY)
  840. {
  841. current.LinkNext(next.Next);
  842. next = next.Next;
  843. finded = true;
  844. break;
  845. }
  846. if (IsInclined)
  847. {
  848. int cnnx = current.BX - next.Next.BX;
  849. int cnny = current.BY - next.Next.BY;
  850. if (Math.Abs(cnnx) == Math.Abs(cnny))
  851. {
  852. int cnx = current.BX - next.BX;
  853. int cny = current.BY - next.BY;
  854. int nnx = next.BX - next.Next.BX;
  855. int nny = next.BY - next.Next.BY;
  856. if ((cnnx == cnx + nnx) && (cnny == cny + nny))
  857. {
  858. current.LinkNext(next.Next);
  859. next = next.Next;
  860. finded = true;
  861. break;
  862. }
  863. }
  864. }
  865. }
  866. if (TouchMapLine(current.PosX, current.PosY, next.Next.PosX, next.Next.PosY))
  867. {
  868. current = next;
  869. break;
  870. }
  871. else
  872. {
  873. current.LinkNext(next.Next);
  874. next = next.Next;
  875. finded = true;
  876. continue;
  877. }
  878. }
  879. }
  880. }
  881. while (finded);
  882. }
  883. #endregion
  884. //---------------------------------------------------------------------------------------------------------------------
  885. #region _MapNodes_
  886. public MMapNode GetMapNode(int bx, int by)
  887. {
  888. if (bx >= 0 && bx < terrain_map.xcount && by >= 0 && by < terrain_map.ycount)
  889. {
  890. return this.terrain_map.getMapNode(bx, by);
  891. }
  892. return null;
  893. }
  894. public MMapNode GetMapNodeByPos(float x, float y)
  895. {
  896. int bx = (int)(x / cellw);
  897. int by = (int)(y / cellh);
  898. return GetMapNode(bx, by);
  899. }
  900. public MSpaceAStar.MSpaceNode GetSpaceMapNode(int cx, int cy)
  901. {
  902. if (space_div != null)
  903. {
  904. return space_div.SpaceMap.getSpaceNode(cx, cy);
  905. }
  906. return null;
  907. }
  908. public void PosToBlock(float x, float y, out int bx, out int by)
  909. {
  910. bx = (int)(x / cellw);
  911. by = (int)(y / cellh);
  912. }
  913. public bool InRangeByBlock(int bx, int by)
  914. {
  915. if (bx >= 0 && bx < manhattan_map.XCount && by >= 0 && by < manhattan_map.YCount)
  916. {
  917. return true;
  918. }
  919. return false;
  920. }
  921. public bool TouchMapBlock(int bx, int by)
  922. {
  923. var node = GetMapNode(bx, by);
  924. if (node == null)
  925. return true;
  926. return node.Blocked;
  927. }
  928. public bool TouchMapRect(float x0, float y0, float x1, float y1)
  929. {
  930. if (x0 > x1) CUtils.Swap(ref x0, ref x1);
  931. if (y0 > y1) CUtils.Swap(ref y0, ref y1);
  932. int bx0 = (int)(x0 / cellw);
  933. int by0 = (int)(y0 / cellh);
  934. int bx1 = (int)(x1 / cellw) + 1;
  935. int by1 = (int)(y1 / cellh) + 1;
  936. if (bx0 < 0) bx0 = 0;
  937. if (by0 < 0) by0 = 0;
  938. if (bx1 >= terrain_map.xcount) bx1 = terrain_map.xcount - 1;
  939. if (by1 >= terrain_map.ycount) by1 = terrain_map.ycount - 1;
  940. for (int by = by0; by <= by1; by++)
  941. {
  942. for (int bx = bx0; bx <= bx1; bx++)
  943. {
  944. MMapNode node = terrain_map.getMapNode(bx, by);
  945. if (node == null || node.Blocked)
  946. {
  947. return true;
  948. }
  949. }
  950. }
  951. return false;
  952. }
  953. /// <summary>
  954. ///
  955. /// </summary>
  956. /// <param name="x0"></param>
  957. /// <param name="y0"></param>
  958. /// <param name="x1"></param>
  959. /// <param name="y1"></param>
  960. /// <returns></returns>
  961. public bool TouchMapLine(float x0, float y0, float x1, float y1)
  962. {
  963. int bx0 = (int)(x0 / cellw);
  964. int by0 = (int)(y0 / cellh);
  965. int bx1 = (int)(x1 / cellw);
  966. int by1 = (int)(y1 / cellh);
  967. if (bx0 > bx1) CUtils.Swap(ref bx0, ref bx1);
  968. if (by0 > by1) CUtils.Swap(ref by0, ref by1);
  969. if (bx0 < 0) bx0 = 0;
  970. if (by0 < 0) by0 = 0;
  971. if (bx1 >= terrain_map.xcount) bx1 = terrain_map.xcount - 1;
  972. if (by1 >= terrain_map.ycount) by1 = terrain_map.ycount - 1;
  973. for (int by = by0; by <= by1; by++)
  974. {
  975. for (int bx = bx0; bx <= bx1; bx++)
  976. {
  977. MMapNode node = terrain_map.getMapNode(bx, by);
  978. if (node == null)
  979. {
  980. return true;
  981. }
  982. else if (node.TouchLine(x0, y0, x1, y1))
  983. {
  984. return true;
  985. }
  986. }
  987. }
  988. return false;
  989. }
  990. /// <summary>
  991. /// 获得线段和地图碰撞最近的焦点
  992. /// </summary>
  993. /// <param name="x0">起始点X</param>
  994. /// <param name="y0">起始点Y</param>
  995. /// <param name="x1">结束点X</param>
  996. /// <param name="y1">结束点Y</param>
  997. /// <param name="touch_x">接触点</param>
  998. /// <param name="touch_y">接触点</param>
  999. /// <param name="touch_distance">接触距离</param>
  1000. /// <returns></returns>
  1001. public bool GetLineTouchPoint(float x0, float y0, float x1, float y1, out float touch_x, out float touch_y, out float touch_distance)
  1002. {
  1003. int bx0 = (int)(x0 / cellw);
  1004. int by0 = (int)(y0 / cellh);
  1005. int bx1 = (int)(x1 / cellw);
  1006. int by1 = (int)(y1 / cellh);
  1007. if (bx0 > bx1) CUtils.Swap(ref bx0, ref bx1);
  1008. if (by0 > by1) CUtils.Swap(ref by0, ref by1);
  1009. if (bx0 < 0) bx0 = 0;
  1010. if (by0 < 0) by0 = 0;
  1011. if (bx1 >= terrain_map.xcount) bx1 = terrain_map.xcount - 1;
  1012. if (by1 >= terrain_map.ycount) by1 = terrain_map.ycount - 1;
  1013. bool ret = false;
  1014. float t_d = 0;
  1015. float t_x = 0;
  1016. float t_y = 0;
  1017. touch_x = 0;
  1018. touch_y = 0;
  1019. touch_distance = float.MaxValue;
  1020. for (int by = by0; by <= by1; by++)
  1021. {
  1022. for (int bx = bx0; bx <= bx1; bx++)
  1023. {
  1024. MMapNode node = terrain_map.getMapNode(bx, by);
  1025. if (node != null && node.GetLineTouchPoint(x0, y0, x1, y1, out t_x, out t_y, out t_d))
  1026. {
  1027. if (t_d < touch_distance)
  1028. {
  1029. touch_distance = t_d;
  1030. touch_x = t_x;
  1031. touch_y = t_y;
  1032. }
  1033. ret = true;
  1034. }
  1035. }
  1036. }
  1037. return ret;
  1038. }
  1039. public enum TryMoveToMapBorderResult : byte
  1040. {
  1041. ARRIVE = 0,
  1042. TOUCH = 1,
  1043. BLOCK = 2,
  1044. }
  1045. /// <summary>
  1046. /// 尝试移动坐标,如果碰撞则贴在碰撞边缘
  1047. /// </summary>
  1048. /// <param name="x"></param>
  1049. /// <param name="y"></param>
  1050. /// <param name="dx"></param>
  1051. /// <param name="dy"></param>
  1052. /// <returns></returns>
  1053. public TryMoveToMapBorderResult TryMoveToMapBorder(ref float x, ref float y, float dx, float dy)
  1054. {
  1055. TryMoveToMapBorderResult result = TryMoveToMapBorderResult.ARRIVE;
  1056. float oldx = x;
  1057. float oldy = y;
  1058. if (TouchMapBlock((int)((x + dx) / cellw), (int)((y) / cellh)))
  1059. {
  1060. result = TryMoveToMapBorderResult.TOUCH;
  1061. }
  1062. else
  1063. {
  1064. x += dx;
  1065. }
  1066. if (TouchMapBlock((int)((x) / cellw), (int)((y + dy) / cellh)))
  1067. {
  1068. result = TryMoveToMapBorderResult.TOUCH;
  1069. }
  1070. else
  1071. {
  1072. y += dy;
  1073. }
  1074. if (x == oldx && y == oldy)
  1075. {
  1076. result = TryMoveToMapBorderResult.BLOCK;
  1077. }
  1078. return result;
  1079. }
  1080. /// <summary>
  1081. /// 找到附近可过去的随机一点
  1082. /// </summary>
  1083. /// <param name="random"></param>
  1084. /// <param name="x"></param>
  1085. /// <param name="y"></param>
  1086. /// <param name="distance"></param>
  1087. /// <param name="recommend">优先四周无其他阻挡</param>
  1088. /// <returns></returns>
  1089. public MMapNode FindNearRandomMoveableNode(System.Random random, float x, float y, float distance, bool recommend = false)
  1090. {
  1091. int cx1 = (int)((x - distance) / this.cellw) - 1;
  1092. int cy1 = (int)((y - distance) / this.cellh) - 1;
  1093. int cx2 = (int)((x + distance) / this.cellw) + 1;
  1094. int cy2 = (int)((y + distance) / this.cellh) + 1;
  1095. cx1 = Math.Max(cx1, 0);
  1096. cy1 = Math.Max(cy1, 0);
  1097. cx2 = Math.Min(cx2, this.manhattan_map.XCount - 1);
  1098. cy2 = Math.Min(cy2, this.manhattan_map.YCount - 1);
  1099. int x_len = cx2 - cx1 + 1;
  1100. int y_len = cy2 - cy1 + 1;
  1101. if (x_len > 0 && y_len > 0)
  1102. {
  1103. int bx = random.Next(x_len);
  1104. int by = random.Next(y_len);
  1105. for (int iy = 0; iy < y_len; iy++)
  1106. {
  1107. for (int ix = 0; ix < x_len; ix++)
  1108. {
  1109. var ret = terrain_map.getMapNode(
  1110. cx1 + CMath.cycNum(bx, ix, x_len),
  1111. cy1 + CMath.cycNum(by, iy, y_len));
  1112. if (ret != null && !ret.Blocked)
  1113. {
  1114. if (recommend)
  1115. {
  1116. return ToRecommend(ret, cx1, cy1, cx2, cy2);
  1117. }
  1118. else
  1119. {
  1120. return ret;
  1121. }
  1122. }
  1123. }
  1124. }
  1125. }
  1126. return null;
  1127. }
  1128. /// <summary>
  1129. /// 找到附近可过去的随机一点
  1130. /// </summary>
  1131. /// <param name="random"></param>
  1132. /// <param name="x"></param>
  1133. /// <param name="y"></param>
  1134. /// <param name="distance"></param>
  1135. /// <param name="recommend">优先四周无其他阻挡</param>
  1136. /// <returns></returns>
  1137. public MMapNode FindNearRandomMoveableNode(System.Random random, float x, float y, float minDis, float maxDis, bool recommend = false)
  1138. {
  1139. int cx1 = (int)((x - maxDis) / this.cellw) - 1;
  1140. int cy1 = (int)((y - maxDis) / this.cellh) - 1;
  1141. int cx2 = (int)((x + maxDis) / this.cellw) + 1;
  1142. int cy2 = (int)((y + maxDis) / this.cellh) + 1;
  1143. cx1 = Math.Max(cx1, 0);
  1144. cy1 = Math.Max(cy1, 0);
  1145. cx2 = Math.Min(cx2, this.manhattan_map.XCount - 1);
  1146. cy2 = Math.Min(cy2, this.manhattan_map.YCount - 1);
  1147. int x_len = cx2 - cx1 + 1;
  1148. int y_len = cy2 - cy1 + 1;
  1149. int mx1 = (int)((x - minDis) / this.cellw) - 1;
  1150. int my1 = (int)((y - minDis) / this.cellh) - 1;
  1151. int mx2 = (int)((x + minDis) / this.cellw) + 1;
  1152. int my2 = (int)((y + minDis) / this.cellh) + 1;
  1153. mx1 = Math.Max(mx1, 0);
  1154. my1 = Math.Max(my1, 0);
  1155. mx2 = Math.Min(mx2, this.manhattan_map.XCount - 1);
  1156. my2 = Math.Min(my2, this.manhattan_map.YCount - 1);
  1157. int mx_len = mx2 - mx1 + 1;
  1158. int my_len = my2 - my1 + 1;
  1159. if (x_len > 0 && y_len > 0)
  1160. {
  1161. int bx = random.Next(x_len);
  1162. int by = random.Next(y_len);
  1163. int tempX = 0, tempY = 0;
  1164. for (int iy = 0; iy < y_len; iy++)
  1165. {
  1166. for (int ix = 0; ix < x_len; ix++)
  1167. {
  1168. tempX = cx1 + CMath.cycNum(bx, ix, x_len);
  1169. tempY = cy1 + CMath.cycNum(by, iy, y_len);
  1170. if (mx1 < tempX && tempX < mx2 && my1 < tempY && tempY < my2)
  1171. continue;
  1172. var ret = terrain_map.getMapNode(tempX, tempY);
  1173. if (ret != null && !ret.Blocked)
  1174. {
  1175. if (recommend)
  1176. {
  1177. ret = ToRecommend(ret, cx1, cy1, cx2, cy2);
  1178. }
  1179. //if(CMath.includeRectPoint(cx1, cy1, cx2, cy2, ret.PosX, ret.PosY)
  1180. // && !CMath.includeRectPoint(mx1, my1, mx2, my2, ret.PosX, ret.PosY))
  1181. //{
  1182. //}
  1183. //else
  1184. //{
  1185. // System.Console.WriteLine("验证失败");
  1186. //}
  1187. return ret;
  1188. }
  1189. }
  1190. }
  1191. }
  1192. return null;
  1193. }
  1194. /// <summary>
  1195. /// 指定范围可过去的一点.
  1196. /// </summary>
  1197. /// <param name="x"></param>
  1198. /// <param name="y"></param>
  1199. /// <param name="distance"></param>
  1200. /// <param name="recommend"></param>
  1201. /// <returns></returns>
  1202. public MMapNode FindNearMoveableNode(float x, float y, float distance, bool recommend = false)
  1203. {
  1204. int cx1 = (int)((x - distance) / this.cellw) - 1;
  1205. int cy1 = (int)((y - distance) / this.cellh) - 1;
  1206. int cx2 = (int)((x + distance) / this.cellw) + 1;
  1207. int cy2 = (int)((y + distance) / this.cellh) + 1;
  1208. cx1 = Math.Max(cx1, 0);
  1209. cy1 = Math.Max(cy1, 0);
  1210. cx2 = Math.Min(cx2, this.manhattan_map.XCount - 1);
  1211. cy2 = Math.Min(cy2, this.manhattan_map.YCount - 1);
  1212. int x_len = cx2 - cx1 + 1;
  1213. int y_len = cy2 - cy1 + 1;
  1214. if (x_len > 0 && y_len > 0)
  1215. {
  1216. int bx = (x_len);
  1217. int by = (y_len);
  1218. for (int iy = 0; iy < y_len; iy++)
  1219. {
  1220. for (int ix = 0; ix < x_len; ix++)
  1221. {
  1222. var ret = terrain_map.getMapNode(
  1223. cx1 + CMath.cycNum(bx, ix, x_len),
  1224. cy1 + CMath.cycNum(by, iy, y_len));
  1225. if (ret != null && !ret.Blocked)
  1226. {
  1227. if (recommend)
  1228. {
  1229. return ToRecommend(ret, cx1, cy1, cx2, cy2);
  1230. }
  1231. else
  1232. {
  1233. return ret;
  1234. }
  1235. }
  1236. }
  1237. }
  1238. }
  1239. return null;
  1240. }
  1241. /// <summary>
  1242. /// 找到离中心最近的可移动点
  1243. /// </summary>
  1244. /// <param name="sx"></param>
  1245. /// <param name="sy"></param>
  1246. /// <param name="sw"></param>
  1247. /// <param name="sh"></param>
  1248. /// <param name="recommend">优先四周无其他阻挡</param>
  1249. /// <returns></returns>
  1250. public MMapNode FindNearMoveableNodeByBlock(int sx, int sy, int sw, int sh, bool recommend = true)
  1251. {
  1252. int count = Math.Max(sw / 2 + 1, sh / 2 + 1);
  1253. int dx = sx + sw - 1;
  1254. int dy = sy + sh - 1;
  1255. int cx = sx + sw / 2;
  1256. int cy = sy + sh / 2;
  1257. for (int r = 0; r <= count; r++)
  1258. {
  1259. int cx1 = cx - r;
  1260. int cy1 = cy - r;
  1261. int cx2 = cx + r;
  1262. int cy2 = cy + r;
  1263. for (int ix = cx1; ix <= cx2; ix++)
  1264. {
  1265. if ((ix >= sx) && (ix <= dx))
  1266. {
  1267. for (int iy = cy1; iy < cy2; iy++)
  1268. {
  1269. if ((iy >= sy) && (iy <= dy))
  1270. {
  1271. var cn = GetMapNode(ix, iy);
  1272. if (cn != null && !cn.Blocked)
  1273. {
  1274. if (recommend)
  1275. {
  1276. return ToRecommend(cn, sx, sy, dx, dy);
  1277. }
  1278. else
  1279. {
  1280. return cn;
  1281. }
  1282. }
  1283. }
  1284. }
  1285. }
  1286. }
  1287. }
  1288. return null;
  1289. }
  1290. private MMapNode ToRecommend(MMapNode src, int min_x, int min_y, int max_x, int max_y)
  1291. {
  1292. if (src.IsAllCross) return src;
  1293. foreach (int[] offset in near_table_inclined)
  1294. {
  1295. int ix = src.BX + offset[0];
  1296. int iy = src.BY + offset[1];
  1297. if (ix >= min_x && iy >= min_y && ix <= max_x && iy <= max_y)
  1298. {
  1299. var cn = GetMapNode(ix, iy);
  1300. if (cn != null && cn.IsAllCross)
  1301. {
  1302. return cn;
  1303. }
  1304. }
  1305. }
  1306. return src;
  1307. }
  1308. /// <summary>
  1309. /// 检测范围内有无期望的地块
  1310. /// </summary>
  1311. /// <param name="sx"></param>
  1312. /// <param name="sy"></param>
  1313. /// <param name="sw"></param>
  1314. /// <param name="sh"></param>
  1315. /// <param name="expect_block"></param>
  1316. /// <returns></returns>
  1317. private bool CheckNearExpectByBlock(int sx, int sy, int sw, int sh, bool expect_block)
  1318. {
  1319. int cx1 = Math.Max(sx, 0);
  1320. int cy1 = Math.Max(sy, 0);
  1321. int cx2 = Math.Min(sx + sw, this.manhattan_map.XCount - 1);
  1322. int cy2 = Math.Min(sy + sh, this.manhattan_map.YCount - 1);
  1323. for (int cx = cx1; cx <= cx2; ++cx)
  1324. {
  1325. for (int cy = cy1; cy <= cy2; ++cy)
  1326. {
  1327. var cn = terrain_map.getMapNode(cx, cy);
  1328. if (cn == null)
  1329. {
  1330. if (expect_block == false) return false;
  1331. }
  1332. else if (cn.Blocked != expect_block)
  1333. {
  1334. return false;
  1335. }
  1336. }
  1337. }
  1338. return true;
  1339. }
  1340. /// <summary>
  1341. /// 检测范围内希望的地块数量
  1342. /// </summary>
  1343. /// <param name="sx"></param>
  1344. /// <param name="sy"></param>
  1345. /// <param name="sw"></param>
  1346. /// <param name="sh"></param>
  1347. /// <param name="expect_block"></param>
  1348. /// <returns></returns>
  1349. private int GetNearExpectCountByBlock(int sx, int sy, int sw, int sh, bool expect_block)
  1350. {
  1351. int ret = 0;
  1352. int cx1 = Math.Max(sx, 0);
  1353. int cy1 = Math.Max(sy, 0);
  1354. int cx2 = Math.Min(sx + sw, this.manhattan_map.XCount);
  1355. int cy2 = Math.Min(sy + sh, this.manhattan_map.YCount);
  1356. for (int cx = cx1; cx < cx2; ++cx)
  1357. {
  1358. for (int cy = cy1; cy < cy2; ++cy)
  1359. {
  1360. var cn = terrain_map.getMapNode(cx, cy);
  1361. if (cn == null)
  1362. {
  1363. if (expect_block) ret++;
  1364. }
  1365. else if (cn.Blocked == expect_block)
  1366. {
  1367. ret++;
  1368. }
  1369. }
  1370. }
  1371. return ret;
  1372. }
  1373. #endregion
  1374. //---------------------------------------------------------------------------------------------------------------------
  1375. #region _常量_
  1376. private static int[][] near_table_inclined = new int[][]
  1377. {
  1378. new int[]{ 0,-1}, // top
  1379. new int[]{-1, 0}, // left
  1380. new int[]{ 1, 0}, // right
  1381. new int[]{ 0, 1}, // bottom
  1382. new int[]{-1,-1}, // top left
  1383. new int[]{ 1,-1}, // top right
  1384. new int[]{-1, 1}, // bottom left
  1385. new int[]{ 1, 1}, // bottom right
  1386. };
  1387. private static int[][] near_table_cross = new int[][]
  1388. {
  1389. new int[]{ 0,-1}, // top
  1390. new int[]{-1, 0}, // left
  1391. new int[]{ 1, 0}, // right
  1392. new int[]{ 0, 1}, // bottom
  1393. };
  1394. public static int[][] GetNearTables(bool inclined)
  1395. {
  1396. int[][] near_table = inclined ? near_table_inclined : near_table_cross;
  1397. return near_table;
  1398. }
  1399. class DirtyNodes<T>
  1400. {
  1401. private HashMap<T, T> map = new HashMap<T, T>();
  1402. public void AddDirty(T obj) { map.Put(obj, obj); }
  1403. public void Clear() { map.Clear(); }
  1404. public int Count { get { return map.Count; } }
  1405. public ICollection<T> Values { get { return map.Values; } }
  1406. }
  1407. #endregion
  1408. //------------------------------------------------------------------------------------------------------------------
  1409. }
  1410. }