KNpcFindPath.cpp
上传用户:dzyhzl
上传日期:2019-04-29
资源大小:56270k
文件大小:8k
源码类别:

模拟服务器

开发平台:

C/C++

  1. //---------------------------------------------------------------------------
  2. // Sword3 Engine (c) 1999-2000 by Kingsoft
  3. //
  4. // File: KNpcFindPath.cpp
  5. // Date: 2002.01.06
  6. // Code: 边城浪子
  7. // Desc: Obj Class
  8. //---------------------------------------------------------------------------
  9. #include "KCore.h"
  10. #include <math.h>
  11. #include "KMath.h"
  12. #include "KNpcFindPath.h"
  13. #include "KSubWorld.h"
  14. #include "KNpc.h"
  15. #define MAX_FIND_TIMER 30
  16. //-------------------------------------------------------------------------
  17. // 功能:构造函数
  18. //-------------------------------------------------------------------------
  19. KNpcFindPath::KNpcFindPath()
  20. {
  21. m_nDestX = 0;
  22. m_nDestY = 0;
  23. m_nFindTimer = 0;
  24. m_nMaxTimeLong = MAX_FIND_TIMER;
  25. m_nFindState = 0;
  26. m_nPathSide = 0;
  27. m_nFindTimes = 0;
  28. m_NpcIdx = 0;
  29. };
  30. //-------------------------------------------------------------------------
  31. // 功能:初始化
  32. // 参数:nNpc :这个寻路是属于哪个 npc 的
  33. //-------------------------------------------------------------------------
  34. void KNpcFindPath::Init(int nNpc)
  35. {
  36. m_NpcIdx = nNpc;
  37. m_nDestX = 0;
  38. m_nDestY = 0;
  39. m_nFindTimer = 0;
  40. m_nMaxTimeLong = MAX_FIND_TIMER;
  41. m_nFindState = 0;
  42. m_nPathSide = 0;
  43. m_nFindTimes = 0;
  44. }
  45. //-------------------------------------------------------------------------
  46. // 功能:传入当前坐标、方向、目标点坐标、速度,寻路找到下一步应该走的方向
  47. // 返回值;如果返回0:有障碍,不能走了;1,找到一个方向,方向值放在pnGetDir (按64方向);
  48. // -1:到地图外面去了
  49. //-------------------------------------------------------------------------
  50. #define defFIND_PATH_STOP_DISTANCE 64
  51. int KNpcFindPath::GetDir(int nXpos,int nYpos, int nDir, int nDestX, int nDestY, int nMoveSpeed, int *pnGetDir)
  52. {
  53. // 如果距离接近,认为已经走到了
  54. if ( !CheckDistance(nXpos >> 10, nYpos >> 10, nDestX, nDestY, nMoveSpeed))
  55. {
  56. m_nFindTimer = 0;
  57. m_nFindState = 0;
  58. m_nFindTimes = 0;
  59. return 0;
  60. }
  61. // 目标点如果有变化,取消原来的找路状态
  62. if (m_nDestX != nDestX || m_nDestY != nDestY)
  63. {
  64. m_nFindTimer = 0;
  65. m_nFindState = 0;
  66. m_nFindTimes = 0;
  67. m_nDestX = nDestX;
  68. m_nDestY = nDestY;
  69. }
  70. int x, y, nWantDir;
  71. nWantDir = g_GetDirIndex(nXpos >> 10, nYpos >> 10, nDestX, nDestY);
  72. x = g_DirCos(nWantDir, 64) * nMoveSpeed;
  73. y = g_DirSin(nWantDir, 64) * nMoveSpeed;
  74. // 如果有路,直接走
  75. int nCheckBarrier = CheckBarrier(x, y);
  76. if ( nCheckBarrier == 0 )
  77. {
  78. m_nFindState = 0;
  79. *pnGetDir = nWantDir;
  80. return 1;
  81. }
  82. // 地图边缘
  83. else if (nCheckBarrier == 0xff)
  84. {
  85. return -1;
  86. }
  87. int i;
  88. // 从非找路状态进入找路状态
  89. if (m_nFindState == 0)
  90. {
  91. // 如果目标点是障碍而且具体过近,不找了
  92. #ifdef _SERVER
  93. nCheckBarrier = SubWorld[Npc[m_NpcIdx].m_SubWorldIndex].TestBarrier(nDestX, nDestY);
  94. #else
  95. if (Npc[m_NpcIdx].m_RegionIndex >= 0)
  96. nCheckBarrier = SubWorld[0].TestBarrier(nDestX, nDestY);
  97. else
  98. nCheckBarrier = 0xff;
  99. #endif
  100. if (nCheckBarrier != 0 && !CheckDistance(nXpos >> 10, nYpos >> 10, nDestX, nDestY, defFIND_PATH_STOP_DISTANCE))
  101. {
  102. m_nFindTimes = 0;
  103. return 0;
  104. }
  105. // 如果第二次进入拐弯状态,不找了(只拐一次弯)
  106. m_nFindTimes++;
  107. if (m_nFindTimes > 1)
  108. {
  109. m_nFindTimes = 0;
  110. return 0;
  111. }
  112. int nTempDir8, nTempDir64;
  113. nTempDir8 = Dir64To8(nWantDir) + 8;
  114. // 转换成 8 方向后当前方向是否可行
  115. nTempDir64 = Dir8To64(nTempDir8 & 0x07);
  116. x = g_DirCos( nTempDir64, 64 ) * nMoveSpeed;
  117. y = g_DirSin( nTempDir64, 64 ) * nMoveSpeed;
  118. if ( CheckBarrier(x, y) == 0 )
  119. {
  120. m_nFindState = 1;
  121. m_nFindTimer = 0;
  122. if ((nTempDir64 < nWantDir && nWantDir - nTempDir64 <= 4) || (nTempDir64 > nWantDir && nTempDir64 - nWantDir >= 60))
  123. m_nPathSide = 0;
  124. else
  125. m_nPathSide = 1;
  126. *pnGetDir = nTempDir64;
  127. return 1;
  128. }
  129. // 按 8 方向寻找,检查除去正面和背面的另外 6 个方向
  130. for (i = 1; i < 4; i++)
  131. {
  132. nTempDir64 = Dir8To64((nTempDir8 + i) & 0x07);
  133. x = g_DirCos( nTempDir64, 64 ) * nMoveSpeed;
  134. y = g_DirSin( nTempDir64, 64 ) * nMoveSpeed;
  135. if ( CheckBarrier(x, y) == 0 )
  136. {
  137. m_nFindState = 1;
  138. m_nFindTimer = 0;
  139. m_nPathSide = 1;
  140. *pnGetDir = nTempDir64;
  141. return 1;
  142. }
  143. nTempDir64 = Dir8To64((nTempDir8 - i) & 0x07);
  144. x = g_DirCos( nTempDir64, 64 ) * nMoveSpeed;
  145. y = g_DirSin( nTempDir64, 64 ) * nMoveSpeed;
  146. if ( CheckBarrier(x, y) == 0 )
  147. {
  148. m_nFindState = 1;
  149. m_nFindTimer = 0;
  150. m_nPathSide = 0;
  151. *pnGetDir = nTempDir64;
  152. return 1;
  153. }
  154. }
  155. return 0;
  156. }
  157. // 原本是找路状态,继续找路
  158. else
  159. {
  160. // 如果找路时间过长,不找了
  161. if (m_nFindTimer >= m_nMaxTimeLong)
  162. {
  163. m_nFindState = 0;
  164. return 0;
  165. }
  166. m_nFindTimer++;
  167. int nWantDir8, nTempDir64;
  168. nWantDir8 = Dir64To8(nWantDir) + 8;
  169. // 当前方向位于目标方向的右侧
  170. if (m_nPathSide == 1)
  171. {
  172. // 判断是否需要检测当前目标朝向对应的 8 方向上
  173. nTempDir64 = Dir8To64(nWantDir8 & 0x07);
  174. if ((nTempDir64 < nWantDir && nWantDir - nTempDir64 <= 4) || (nTempDir64 > nWantDir && nTempDir64 - nWantDir >= 60))
  175. i = 1;
  176. else
  177. i = 0;
  178. // 拐弯过程
  179. for (; i < 4; i++)
  180. {
  181. nTempDir64 = Dir8To64((nWantDir8 + i) & 0x07);
  182. x = g_DirCos( nTempDir64, 64 ) * nMoveSpeed;
  183. y = g_DirSin( nTempDir64, 64 ) * nMoveSpeed;
  184. if ( CheckBarrier(x, y) == 0 )
  185. {
  186. *pnGetDir = nTempDir64;
  187. return 1;
  188. }
  189. }
  190. m_nFindState = 0;
  191. m_nFindTimer = 0;
  192. return 0;
  193. }
  194. // 当前方向位于目标方向的左侧
  195. else
  196. {
  197. // 判断是否需要检测当前目标朝向对应的 8 方向上
  198. nTempDir64 = Dir8To64(nWantDir8 & 0x07);
  199. if ((nTempDir64 < nWantDir && nWantDir - nTempDir64 <= 4) || (nTempDir64 > nWantDir && nTempDir64 - nWantDir >= 60))
  200. i = 0;
  201. else
  202. i = 1;
  203. // 拐弯过程
  204. for (; i < 4; i++)
  205. {
  206. nTempDir64 = Dir8To64((nWantDir8 - i) & 0x07);
  207. x = g_DirCos( nTempDir64, 64 ) * nMoveSpeed;
  208. y = g_DirSin( nTempDir64, 64 ) * nMoveSpeed;
  209. if ( CheckBarrier(x, y) == 0 )
  210. {
  211. *pnGetDir = nTempDir64;
  212. return 1;
  213. }
  214. }
  215. m_nFindState = 0;
  216. m_nFindTimer = 0;
  217. return 0;
  218. }
  219. }
  220. m_nFindState = 0;
  221. m_nFindTimer = 0;
  222. return 0;
  223. }
  224. //-------------------------------------------------------------------------
  225. // 功能: 64 方向转换为 8 方向
  226. //-------------------------------------------------------------------------
  227. int KNpcFindPath::Dir64To8(int nDir)
  228. {
  229. return ((nDir + 4) >> 3) & 0x07;
  230. }
  231. //-------------------------------------------------------------------------
  232. // 功能: 8 方向转换为 64 方向
  233. //-------------------------------------------------------------------------
  234. int KNpcFindPath::Dir8To64(int nDir)
  235. {
  236. return nDir << 3;
  237. }
  238. //-------------------------------------------------------------------------
  239. // 功能: 判断两点间的直线距离是否大于或等于给定距离
  240. // 返回: 距离小于 nDistance 返回 FALSE ,否则返回 TRUE
  241. //-------------------------------------------------------------------------
  242. BOOL KNpcFindPath::CheckDistance(int x1, int y1, int x2, int y2, int nDistance)
  243. {
  244. return ( (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) >= nDistance * nDistance );
  245. }
  246. //-------------------------------------------------------------------------
  247. // 功能: 判断某个点是否是障碍
  248. //-------------------------------------------------------------------------
  249. int KNpcFindPath::CheckBarrier(int nChangeX, int nChangeY)
  250. {
  251. #ifdef _SERVER
  252. return SubWorld[Npc[m_NpcIdx].m_SubWorldIndex].TestBarrierMin(Npc[m_NpcIdx].m_RegionIndex, Npc[m_NpcIdx].m_MapX, Npc[m_NpcIdx].m_MapY, Npc[m_NpcIdx].m_OffX, Npc[m_NpcIdx].m_OffY, nChangeX, nChangeY);
  253. #else
  254. if (Npc[m_NpcIdx].m_RegionIndex >= 0)
  255. return SubWorld[0].TestBarrierMin(Npc[m_NpcIdx].m_RegionIndex, Npc[m_NpcIdx].m_MapX, Npc[m_NpcIdx].m_MapY, Npc[m_NpcIdx].m_OffX, Npc[m_NpcIdx].m_OffY, nChangeX, nChangeY);
  256. else
  257. return 0xff;
  258. #endif
  259. }