RecastInterface.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using UnityEngine;
  4. namespace ET
  5. {
  6. /// <summary>
  7. /// 用Apoca\recastnavigation-master\RecastDemo\Projects\vs2019\recastnavigation.sln工程编译
  8. /// recastDll.dll,是Release版x64平台编译的结果
  9. /// Aug.28.2020. Liu gang
  10. /// </summary>
  11. public class RecastInterface
  12. {
  13. private const string RecastDLL = "RecastNavDll";
  14. [DllImport(RecastDLL, CallingConvention = CallingConvention.Cdecl)]
  15. private static extern bool recast_init();
  16. [DllImport(RecastDLL, CallingConvention = CallingConvention.Cdecl)]
  17. private static extern void recast_fini();
  18. [DllImport(RecastDLL, CallingConvention = CallingConvention.Cdecl)]
  19. private static extern bool recast_loadmap(int id, char[] path);
  20. [DllImport(RecastDLL, CallingConvention = CallingConvention.Cdecl)]
  21. private static extern bool recast_freemap(int id);
  22. [DllImport(RecastDLL, CallingConvention = CallingConvention.Cdecl)]
  23. private static extern int recast_findpath(int id, float[] spos, float[] epos);
  24. [DllImport(RecastDLL, CallingConvention = CallingConvention.Cdecl)]
  25. private static extern bool recast_smooth(int id, float step_size, float slop);
  26. [DllImport(RecastDLL, CallingConvention = CallingConvention.Cdecl)]
  27. private static extern int recast_raycast(int id, float[] spos, float[] epos);
  28. [DllImport(RecastDLL, CallingConvention = CallingConvention.Cdecl)]
  29. private static extern int recast_getcountpoly(int id);
  30. [DllImport(RecastDLL, CallingConvention = CallingConvention.Cdecl)]
  31. private static extern int recast_getcountsmooth(int id);
  32. [DllImport(RecastDLL, CallingConvention = CallingConvention.Cdecl)]
  33. private static extern IntPtr recast_getpathpoly(int id);
  34. [DllImport(RecastDLL, CallingConvention = CallingConvention.Cdecl)]
  35. private static extern IntPtr recast_getpathsmooth(int id);
  36. [DllImport(RecastDLL, CallingConvention = CallingConvention.Cdecl)]
  37. private static extern IntPtr recast_getfixposition(int id, float[] pos);
  38. [DllImport(RecastDLL, CallingConvention = CallingConvention.Cdecl)]
  39. private static extern IntPtr recast_gethitposition(int id);
  40. /// <summary>
  41. /// 初始化Recast引擎
  42. /// </summary>
  43. /// <returns></returns>
  44. public static bool Init()
  45. {
  46. return recast_init();
  47. }
  48. /// <summary>
  49. /// 结束化Recast引擎
  50. /// </summary>
  51. public static void Fini()
  52. {
  53. recast_fini();
  54. }
  55. /// <summary>
  56. /// 加载地图数据,支持同时加载多张地图
  57. /// </summary>
  58. /// <param name="id">地图Id</param>
  59. /// <param name="path">地图文件名(包含路径)</param>
  60. /// <returns></returns>
  61. public static bool LoadMap(int id, char[] path)
  62. {
  63. if (path == null || path.Length == 0)
  64. return false;
  65. return recast_loadmap(id, path);
  66. }
  67. /// <summary>
  68. /// 释放地图数据
  69. /// </summary>
  70. /// <param name="id">地图Id</param>
  71. /// <returns></returns>
  72. public static bool FreeMap(int id)
  73. {
  74. return recast_freemap(id);
  75. }
  76. public static Vector3 SPos = new Vector3();
  77. public static Vector3 EPos = new Vector3();
  78. /// <summary>
  79. /// 寻路
  80. /// </summary>
  81. /// <param name="id">地图Id</param>
  82. /// <param name="spos">起点三维坐标</param>
  83. /// <param name="epos">终点三维坐标</param>
  84. /// <returns></returns>
  85. public static bool FindPath(int id, Vector3 spos, Vector3 epos)
  86. {
  87. {
  88. float[] fixPos = fixposition(id, spos);
  89. if (fixPos != null)
  90. {
  91. spos.y = fixPos[1];
  92. }
  93. else
  94. {
  95. Console.WriteLine(string.Concat("错误:", ($"Recast寻路 FindPath Error:- 起点非法 - spos:{spos} - MapId:{id}")));
  96. }
  97. SPos = spos;
  98. }
  99. {
  100. float[] fixPos = fixposition(id, epos);
  101. if (fixPos != null)
  102. {
  103. epos.y = fixPos[1];
  104. }
  105. else
  106. {
  107. Console.WriteLine(string.Concat("错误:",($"Recast寻路 FindPath Error:- 终点非法 - epos:{epos} - MapId:{id}")));
  108. }
  109. EPos = epos;
  110. }
  111. dtStatus status = (dtStatus) recast_findpath(id, new[] { -spos.x, spos.y, spos.z }, new[] { -epos.x, epos.y, epos.z });
  112. if (dtStatusFailed(status))
  113. {
  114. dtStatus statusDetail = status & dtStatus.DT_STATUS_DETAIL_MASK;
  115. string _strLastError = $"Recast寻路 FindPath Error:寻路失败!错误码<" + statusDetail + $"> - MapId:{id}";
  116. if (statusDetail == dtStatus.DT_COORD_INVALID)
  117. {
  118. _strLastError += " - 坐标非法!From<" + spos + "> To<" + epos + $"> - MapId:{id}";
  119. }
  120. Console.WriteLine(string.Concat("错误:",_strLastError));
  121. return false;
  122. }
  123. else if (dtStatusInProgress(status))
  124. {
  125. string _strLastError = $"Recast寻路 Error:寻路尚未结束!- MapId:{id}";
  126. Console.WriteLine(string.Concat("错误:",_strLastError));
  127. return false;
  128. }
  129. return true;
  130. }
  131. /// <summary>
  132. /// 寻路以后,需要调用本函数,得到真实路径,这条路径可以是很平滑的路径
  133. /// BUG FIX:如果Smooth函数的第一个参数设置为5,则可能找到的路线非常长(节点达到2048)
  134. /// </summary>
  135. /// <param name="id">地图Id</param>
  136. /// <param name="step_size">平滑系数,数值越小,越平滑;如果给0,则自动变为0.5</param>
  137. /// <param name="slop">用途不明(但肯定不影响平滑),如果给0,则自动变为0.01</param>
  138. /// <returns></returns>
  139. public static bool Smooth(int id, float step_size, float slop)
  140. {
  141. return recast_smooth(id, step_size, slop);
  142. }
  143. /// <summary>
  144. /// 射线检测
  145. /// </summary>
  146. /// <param name="id">地图Id</param>
  147. /// <param name="spos">起点三维坐标</param>
  148. /// <param name="epos">终点三维坐标</param>
  149. /// <returns></returns>
  150. public static bool Raycast(int id, Vector3 spos, Vector3 epos)
  151. {
  152. dtStatus status = (dtStatus) recast_raycast(id, new float[] { -spos.x, spos.y, spos.z }, new float[] { -epos.x, epos.y, epos.z });
  153. if (dtStatusFailed(status))
  154. {
  155. dtStatus statusDetail = status & dtStatus.DT_STATUS_DETAIL_MASK;
  156. string _strLastError = "Recast寻路 Raycast Error:寻路失败!错误码<" + statusDetail + $"> - MapId:{id}";
  157. if (statusDetail == dtStatus.DT_COORD_INVALID)
  158. {
  159. _strLastError += " - 坐标非法!From<" + spos + "> To<" + epos + $"> - MapId:{id}";
  160. }
  161. Console.WriteLine(string.Concat("错误:",_strLastError));
  162. return false;
  163. }
  164. else if (dtStatusInProgress(status))
  165. {
  166. string _strLastError = $"Recast寻路 Error:寻路尚未结束! - MapId:{id}";
  167. Console.WriteLine(string.Concat("错误:",_strLastError));
  168. return false;
  169. }
  170. return true;
  171. }
  172. /// <summary>
  173. /// 获取射线检测的碰撞点
  174. /// <param name="id">地图Id</param>
  175. /// <returns></returns>
  176. public static float[] getHitPosition(int id)
  177. {
  178. unsafe
  179. {
  180. try
  181. {
  182. IntPtr hitPos = recast_gethitposition(id);
  183. float[] arrHitPos = new float[3];
  184. if (hitPos.ToPointer() != null)
  185. {
  186. Marshal.Copy(hitPos, arrHitPos, 0, 3);
  187. arrHitPos[0] = -arrHitPos[0];
  188. return arrHitPos;
  189. }
  190. else
  191. {
  192. return null;
  193. }
  194. }
  195. catch (Exception e)
  196. {
  197. Console.WriteLine(string.Concat("错误:",($"RecstInterface getHitPosition Exception! - {e}")));
  198. return null;
  199. }
  200. }
  201. }
  202. /// <summary>
  203. /// 在mesh中修正坐标高度
  204. /// 如果你给的Y坐标太低了,则可能会落到附近其他更低的地方
  205. /// <param name="id">地图Id</param>
  206. /// <returns></returns>
  207. public static float[] fixposition(int id, Vector3 pos)
  208. {
  209. unsafe
  210. {
  211. try
  212. {
  213. IntPtr fixPos = recast_getfixposition(id, new float[] { -pos.x, pos.y, pos.z }); // (pos.y+1)抬高一点计算
  214. float[] arrFixPos = new float[3];
  215. if (fixPos.ToPointer() != null)
  216. {
  217. Marshal.Copy(fixPos, arrFixPos, 0, 3);
  218. arrFixPos[0] = -arrFixPos[0];
  219. return arrFixPos;
  220. }
  221. else
  222. {
  223. return null;
  224. }
  225. }
  226. catch (Exception e)
  227. {
  228. Console.WriteLine(string.Concat("错误:",($"RecstInterface fixposition Exception! - {e}")));
  229. return null;
  230. }
  231. }
  232. }
  233. public static int[] GetPathPoly(int id, out int polyCount)
  234. {
  235. unsafe
  236. {
  237. try
  238. {
  239. // https://bbs.csdn.net/topics/392618929?list=676344
  240. polyCount = recast_getcountpoly(id);
  241. IntPtr polys = recast_getpathpoly(id);
  242. if (polys.ToPointer() != null)
  243. {
  244. int[] arrPolys = new int[polyCount];
  245. Marshal.Copy(polys, arrPolys, 0, polyCount);
  246. return arrPolys;
  247. }
  248. return null;
  249. }
  250. catch (Exception e)
  251. {
  252. polyCount = 0;
  253. Console.WriteLine(string.Concat("错误:",($"RecstInterface fixposition Exception! - {e}")));
  254. return null;
  255. }
  256. }
  257. }
  258. public static float[] GetPathSmooth(int id, out int smoothCount)
  259. {
  260. unsafe
  261. {
  262. try
  263. {
  264. int polyCount = recast_getcountpoly(id);
  265. smoothCount = recast_getcountsmooth(id);
  266. IntPtr smooths = recast_getpathsmooth(id);
  267. float[] arrSmooths = new float[smoothCount * 3];
  268. Marshal.Copy(smooths, arrSmooths, 0, smoothCount * 3);
  269. for (int i = 0; i < smoothCount; ++i)
  270. {
  271. arrSmooths[i * 3] = -arrSmooths[i * 3];
  272. }
  273. return arrSmooths;
  274. }
  275. catch (Exception e)
  276. {
  277. smoothCount = 0;
  278. Console.WriteLine(string.Concat("错误:",($"RecstInterface fixposition Exception! - {e}")));
  279. return null;
  280. }
  281. }
  282. }
  283. [Flags]
  284. public enum dtStatus
  285. {
  286. DT_FAILURE = 1 << 31,
  287. DT_SUCCESS = 1 << 30,
  288. DT_IN_PROGRESS = 1 << 29,
  289. DT_STATUS_DETAIL_MASK = 0x0ffffff,
  290. DT_WRONG_MAGIC = 1 << 0,
  291. DT_WRONG_VERSION = 1 << 1,
  292. DT_OUT_OF_MEMORY = 1 << 2,
  293. DT_INVALID_PARAM = 1 << 3,
  294. DT_BUFFER_TOO_SMALL = 1 << 4,
  295. DT_OUT_OF_NODES = 1 << 5,
  296. DT_PARTIAL_RESULT = 1 << 6,
  297. DT_ALREADY_OCCUPIED = 1 << 7,
  298. DT_COORD_INVALID = 1 << 13,
  299. }
  300. // Returns true of status is success.
  301. public static bool dtStatusSucceed(dtStatus status)
  302. {
  303. return (status & dtStatus.DT_SUCCESS) != 0;
  304. }
  305. // Returns true of status is failure.
  306. public static bool dtStatusFailed(dtStatus status)
  307. {
  308. return (status & dtStatus.DT_FAILURE) != 0;
  309. }
  310. // Returns true of status is in progress.
  311. public static bool dtStatusInProgress(dtStatus status)
  312. {
  313. return (status & dtStatus.DT_IN_PROGRESS) != 0;
  314. }
  315. // Returns true if specific detail is set.
  316. public static bool dtStatusDetail(dtStatus status, uint detail)
  317. {
  318. return ((uint) status & detail) != 0;
  319. }
  320. }
  321. }