Motions.cs 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  1. using System;
  2. using System.Collections.Generic;
  3. using CommonLang.Vector;
  4. using CommonLang;
  5. using CommonAI.Zone.Instance;
  6. using CommonAI.RTS.Manhattan;
  7. using CommonLang.IO;
  8. namespace CommonAI.Zone.Helper
  9. {
  10. public class MoveHelper
  11. {
  12. public static readonly int POS_PRECISION = 255;
  13. public static readonly float ToDirectionD8_VALUE = (float)POS_PRECISION /CMath.PI_MUL_2;
  14. /// <summary>
  15. /// 更新速度
  16. /// </summary>
  17. public static void UpdateSpeed(int intervalMS, ref float speedSec, float addSec, float accSec)
  18. {
  19. float add = 0;
  20. float acc = 0;
  21. if (addSec != 0)
  22. {
  23. add = MoveHelper.GetDistance(intervalMS, addSec);
  24. }
  25. if (accSec != 0)
  26. {
  27. acc = MoveHelper.GetDistance(intervalMS, speedSec * accSec);
  28. }
  29. speedSec += (add + acc);
  30. }
  31. public static void UpdateSpeed(int intervalMS, ref float speedSec, float addSec, float accSec, float speedMin, float speedMax)
  32. {
  33. float add = 0;
  34. float acc = 0;
  35. if (addSec != 0)
  36. {
  37. add = MoveHelper.GetDistance(intervalMS, addSec);
  38. }
  39. if (accSec != 0)
  40. {
  41. acc = MoveHelper.GetDistance(intervalMS, speedSec * accSec);
  42. }
  43. speedSec += (add + acc);
  44. if (speedSec > speedMax) { speedSec = speedMax; }
  45. if (speedSec < speedMin) { speedSec = speedMin; }
  46. }
  47. public static void UpdateMoveDistance(int intervalMS, ref float moveDistance, float speed)
  48. {
  49. moveDistance += MoveHelper.GetDistance(intervalMS, speed);
  50. }
  51. #region IO
  52. public static byte ToDirectionD8(float d)
  53. {
  54. return (byte)(CMath.OpitimizeRadians(d) * ToDirectionD8_VALUE);
  55. }
  56. public static float ToDirectionF32(byte d8)
  57. {
  58. return d8 * CMath.PI_MUL_2 / POS_PRECISION;
  59. }
  60. public static ushort ToPos16(float x)
  61. {
  62. return (ushort)(x * POS_PRECISION);
  63. }
  64. public static float ToPosF32(ushort x)
  65. {
  66. return ((float)x) / POS_PRECISION;
  67. }
  68. public static void WritePos(bool half, float x, IOutputStream output)
  69. {
  70. if (half)
  71. {
  72. output.PutU16(ToPos16(x));
  73. }
  74. else
  75. {
  76. output.PutF32(x);
  77. }
  78. }
  79. public static void WritePos(bool half, float x, float y, IOutputStream output)
  80. {
  81. if (half)
  82. {
  83. output.PutU16(ToPos16(x));
  84. output.PutU16(ToPos16(y));
  85. }
  86. else
  87. {
  88. output.PutF32(x);
  89. output.PutF32(y);
  90. }
  91. }
  92. public static void WriteDirection(bool half, float direction, IOutputStream output)
  93. {
  94. if (half)
  95. {
  96. output.PutU8(ToDirectionD8(direction));
  97. }
  98. else
  99. {
  100. output.PutF32(direction);
  101. }
  102. }
  103. public static void WritePosAndDirection(bool half, float x, float y, float direction, IOutputStream output)
  104. {
  105. if (half)
  106. {
  107. output.PutU16(ToPos16(x));
  108. output.PutU16(ToPos16(y));
  109. output.PutU8(ToDirectionD8(direction));
  110. }
  111. else
  112. {
  113. output.PutF32(x);
  114. output.PutF32(y);
  115. output.PutF32(direction);
  116. }
  117. }
  118. public static void ReadPos(bool half, out float x, IInputStream input)
  119. {
  120. if (half)
  121. {
  122. x = ToPosF32(input.GetU16());
  123. }
  124. else
  125. {
  126. x = input.GetF32();
  127. }
  128. }
  129. public static void ReadPos(bool half, out float x, out float y, IInputStream input)
  130. {
  131. if (half)
  132. {
  133. x = ToPosF32(input.GetU16());
  134. y = ToPosF32(input.GetU16());
  135. }
  136. else
  137. {
  138. x = input.GetF32();
  139. y = input.GetF32();
  140. }
  141. }
  142. public static void ReadPos(bool half, ref Vector2 pos, IInputStream input)
  143. {
  144. if (half)
  145. {
  146. pos.SetX(ToPosF32(input.GetU16()));
  147. pos.SetY(ToPosF32(input.GetU16()));
  148. }
  149. else
  150. {
  151. pos.SetX(input.GetF32());
  152. pos.SetY(input.GetF32());
  153. }
  154. }
  155. public static void ReadDirection(bool half, out float direction, IInputStream input)
  156. {
  157. if (half)
  158. {
  159. direction = ToDirectionF32(input.GetU8());
  160. }
  161. else
  162. {
  163. direction = input.GetF32();
  164. }
  165. }
  166. public static void ReadPosAndDirection(bool half, out float x, out float y, out float direction, IInputStream input)
  167. {
  168. if (half)
  169. {
  170. x = ToPosF32(input.GetU16());
  171. y = ToPosF32(input.GetU16());
  172. direction = ToDirectionF32(input.GetU8());
  173. }
  174. else
  175. {
  176. x = input.GetF32();
  177. y = input.GetF32();
  178. direction = input.GetF32();
  179. }
  180. }
  181. #endregion
  182. //------------------------------------------------------------------------------------
  183. public static float GetDistance(int timeMS, float speedSEC)
  184. {
  185. return speedSEC * timeMS / 1000f;
  186. }
  187. /// <summary>
  188. /// 转身算法
  189. /// </summary>
  190. /// <param name="dstD">目标角度</param>
  191. /// <param name="curD">当前角度</param>
  192. /// <param name="turnSpeedSEC">角速度</param>
  193. /// <param name="intervalMS">时间间隔</param>
  194. /// <returns></returns>
  195. public static float DirectionChange(float dstD, float curD, float turnSpeedSEC, int intervalMS)
  196. {
  197. if (turnSpeedSEC > 0)
  198. {
  199. float delta = turnSpeedSEC * intervalMS / 1000f;
  200. float dd = CMath.OpitimizeRadians(dstD) + CMath.PI_MUL_2;
  201. float cd = CMath.OpitimizeRadians(curD) + CMath.PI_MUL_2;
  202. float distanceL = Math.Abs(dd - cd);
  203. float distanceR = CMath.PI_MUL_2 - distanceL;
  204. if (distanceL > distanceR)
  205. {
  206. if (distanceR <= delta)
  207. {
  208. return dstD;
  209. }
  210. if (dd > cd)
  211. {
  212. curD -= delta;
  213. }
  214. else
  215. {
  216. curD += delta;
  217. }
  218. }
  219. else
  220. {
  221. if (distanceL <= delta)
  222. {
  223. return dstD;
  224. }
  225. if (dd > cd)
  226. {
  227. curD += delta;
  228. }
  229. else
  230. {
  231. curD -= delta;
  232. }
  233. }
  234. return curD;
  235. }
  236. return dstD;
  237. }
  238. /// <summary>
  239. /// 导弹一样飞向目标,并自动调整方向
  240. /// </summary>
  241. /// <param name="pos"></param>
  242. /// <param name="direction"></param>
  243. /// <param name="targetX"></param>
  244. /// <param name="targetY"></param>
  245. /// <param name="speedSEC"></param>
  246. /// <param name="turnSpeedSEC"></param>
  247. /// <param name="intervalMS"></param>
  248. public static void MoveToTargetTunning(ref Vector2 sPos, ref float direction, float targetX, float targetY, float speedSEC, float turnSpeedSEC, int intervalMS)
  249. {
  250. float dstD = MathVector.getDegree(targetX - sPos.X, targetY - sPos.Y);
  251. direction = DirectionChange(dstD, direction, turnSpeedSEC, intervalMS);
  252. MathVector.movePolar(ref sPos, direction, speedSEC, intervalMS);
  253. }
  254. /// <summary>
  255. /// 预估击飞到落下的时间
  256. /// </summary>
  257. /// <param name="z">要计算的高度</param>
  258. /// <param name="z_speed">Z速度</param>
  259. /// <param name="z_limit">Z坐标上限</param>
  260. /// <param name="gravity">重力加速度</param>
  261. /// <param name="intervalMS">时间精度,越小越精确,一般10足够精度</param>
  262. /// <returns></returns>
  263. public static int CalculateFlyTimeMS(float z, float z_speed, float z_limit, float gravity, int intervalMS = 10)
  264. {
  265. int time = 0;
  266. float tick_g = GetDistance(intervalMS, gravity);
  267. do
  268. {
  269. time += intervalMS;
  270. float sd = GetDistance(intervalMS, z_speed);
  271. z += sd;
  272. if (z < 0)
  273. {
  274. time -= (int)Math.Abs(intervalMS * (z / sd));
  275. }
  276. if (z_limit != 0 && z_speed > 0 && z > z_limit)
  277. {
  278. z_speed = 0;
  279. }
  280. z_speed -= tick_g;
  281. }
  282. while (z > 0);
  283. return time;
  284. }
  285. /// <summary>
  286. /// 给定最大距离和总时间,计算当前抛物线高度
  287. /// y = ax2 + bx + c;
  288. /// </summary>
  289. /// <param name="maxHeight"></param>
  290. /// <param name="totalTimeMS"></param>
  291. /// <param name="currentTimeMS"></param>
  292. /// <returns></returns>
  293. public static float CalulateParabolicHeight(float maxHeight, int totalTimeMS, int currentTimeMS)
  294. {
  295. float pct = currentTimeMS / (float)totalTimeMS;
  296. // 用正弦函数模拟 //
  297. float y = (float)(Math.Sin(pct * CMath.PI_F) * maxHeight);
  298. return y;
  299. }
  300. /// <summary>
  301. /// 计算单位击退方向
  302. /// </summary>
  303. /// <param name="damage">受击者</param>
  304. /// <param name="attacker">攻击者</param>
  305. /// <param name="mtype"></param>
  306. /// <returns></returns>
  307. public static float CalculateHitMoveDirection(InstanceUnit damage, InstanceZoneObject attacker, AttackProp.HitMoveType mtype)
  308. {
  309. switch (mtype)
  310. {
  311. case AttackProp.HitMoveType.BySenderPosition:
  312. return MathVector.getDegree(attacker.X, attacker.Y, damage.X, damage.Y);
  313. case AttackProp.HitMoveType.BySenderDirection:
  314. return attacker.Direction;
  315. case AttackProp.HitMoveType.BySenderLeftRight:
  316. float fx = attacker.X;
  317. float fy = attacker.Y;
  318. MathVector.movePolar(ref fx, ref fy, attacker.Direction, 10);
  319. if (CMath.PointOnLine(attacker.X, attacker.Y, fx, fy, damage.X, damage.Y) == CMath.PointOnLineResult.Left)
  320. {
  321. return attacker.Direction - CMath.PI_DIV_2;
  322. }
  323. else
  324. {
  325. return attacker.Direction + CMath.PI_DIV_2;
  326. }
  327. case AttackProp.HitMoveType.ToSenderCenter:
  328. case AttackProp.HitMoveType.ToSenderBodySize:
  329. return attacker.Direction + CMath.PI_F;
  330. }
  331. return damage.Direction + CMath.PI_F;
  332. }
  333. }
  334. public class PopupKeyFrames<K> : IComparer<K> where K : BaseKeyFrame
  335. {
  336. readonly private List<K> list = new List<K>();
  337. public int Count
  338. {
  339. get { return list.Count; }
  340. }
  341. public PopupKeyFrames()
  342. {
  343. }
  344. public void AddRange(ICollection<K> frames)
  345. {
  346. list.AddRange(frames);
  347. list.Sort(this);
  348. }
  349. /// <summary>
  350. /// 取出所有到时间的关键帧
  351. /// </summary>
  352. /// <param name="passTimeMS"></param>
  353. /// <param name="ret"></param>
  354. /// <returns></returns>
  355. public int PopKeyFrames(int passTimeMS, List<K> ret = null)
  356. {
  357. int count = 0;
  358. while (list.Count > 0)
  359. {
  360. int i = list.Count - 1;
  361. K kf = list[i];
  362. //不足一帧的,当帧处理
  363. if (kf.FrameMS <= passTimeMS + XmdsConstConfig.GAME_UPDATE_INTERVAL_MS)
  364. {
  365. list.RemoveAt(i);
  366. if (ret != null) { ret.Add(kf); }
  367. count++;
  368. }
  369. else
  370. {
  371. return count;
  372. }
  373. }
  374. return count;
  375. }
  376. public int Compare(K x, K y)
  377. {
  378. return y.FrameMS - x.FrameMS;
  379. }
  380. }
  381. public enum MoveResult : byte
  382. {
  383. MOVE_SMOOTH = 0,
  384. /// <summary>
  385. /// 标志状态,本次移动任何方向接触过地图
  386. /// </summary>
  387. MOVE_RESULT_TOUCH_MAP_ALL = 0x10,
  388. /// <summary>
  389. /// 标志状态,阻挡的单位同意让开
  390. /// </summary>
  391. MOVE_RESULT_TOUCH_OBJ_GETAWAY = 0x20,
  392. /// <summary>
  393. /// 标志状态,本次移动等等
  394. /// </summary>
  395. MOVE_RESULT_HOLD = 0x40,
  396. /// <summary>
  397. /// 标志状态,无法移动
  398. /// </summary>
  399. MOVE_RESULT_NO_WAY = 0x80,
  400. /// <summary>
  401. /// 标志判断,到达目标
  402. /// </summary>
  403. MOVE_RESULT_ARRIVED = 0x01,
  404. /// <summary>
  405. /// 标志判断,被单位阻挡
  406. /// </summary>
  407. MOVE_RESULT_BLOCK_OBJ = 0x02,
  408. /// <summary>
  409. /// 标志判断,被地图阻挡
  410. /// </summary>
  411. MOVE_RESULT_BLOCK_MAP = 0x04,
  412. /// <summary>
  413. /// 标志判断,没有达到预期距离或者移动距离太小
  414. /// </summary>
  415. MOVE_RESULT_MIN_STEP = 0x08,
  416. /// <summary>
  417. /// 【标志判断组】,被任何东西阻挡
  418. /// </summary>
  419. RESULTS_BLOCK_ANY = MOVE_RESULT_BLOCK_OBJ | MOVE_RESULT_BLOCK_MAP,
  420. /// <summary>
  421. /// 【标志判断】,移动结束(被阻挡或者到达目标)
  422. /// </summary>
  423. RESULTS_MOVE_END = MOVE_RESULT_ARRIVED | MOVE_RESULT_BLOCK_OBJ | MOVE_RESULT_BLOCK_MAP | MOVE_RESULT_NO_WAY,
  424. }
  425. public enum MoveImpactResult : byte
  426. {
  427. MOVE_SMOOTH = MoveResult.MOVE_SMOOTH,
  428. /// <summary>
  429. /// 标志状态,本次移动任何方向接触过地图
  430. /// </summary>
  431. MOVE_RESULT_TOUCH_MAP = MoveResult.MOVE_RESULT_TOUCH_MAP_ALL,
  432. /// <summary>
  433. /// 标志状态,阻挡的单位同意让开
  434. /// </summary>
  435. MOVE_RESULT_TOUCH_OBJ = MoveResult.MOVE_RESULT_TOUCH_OBJ_GETAWAY,
  436. /// <summary>
  437. /// 标志判断,被单位阻挡
  438. /// </summary>
  439. MOVE_RESULT_BLOCK_OBJ = MoveResult.MOVE_RESULT_BLOCK_OBJ,
  440. /// <summary>
  441. /// 标志判断,被地图阻挡
  442. /// </summary>
  443. MOVE_RESULT_BLOCK_MAP = MoveResult.MOVE_RESULT_BLOCK_MAP,
  444. /// <summary>
  445. /// 标志判断,没有达到预期距离或者移动距离太小
  446. /// </summary>
  447. MOVE_RESULT_MIN_STEP = MoveResult.MOVE_RESULT_MIN_STEP,
  448. /// <summary>
  449. /// 【标志判断组】,被任何东西阻挡
  450. /// </summary>
  451. RESULTS_CAN_NOT_MOVE = MOVE_RESULT_BLOCK_OBJ | MOVE_RESULT_BLOCK_MAP | MOVE_RESULT_MIN_STEP,
  452. }
  453. public struct MoveBlockResult
  454. {
  455. public MoveResult result;
  456. public InstanceZoneObject obj;
  457. public MoveBlockResult(MoveResult r)
  458. {
  459. this.result = r;
  460. this.obj = null;
  461. }
  462. public bool HasFlag(MoveResult flag)
  463. {
  464. return (result & flag) != 0;
  465. }
  466. }
  467. public struct TMoveTarget : IPositionObject
  468. {
  469. private float x;
  470. private float y;
  471. public TMoveTarget(float x, float y)
  472. {
  473. this.x = x;
  474. this.y = y;
  475. }
  476. public float X { get { return x; } }
  477. public float Y { get { return y; } }
  478. public float Direction { get { return 0; } }
  479. public float RadiusSize { get { return 0; } }
  480. }
  481. public class MoveAI
  482. {
  483. public readonly InstanceUnit unit;
  484. public readonly InstanceZone zone;
  485. private MoveTurnPosObject turnLR;
  486. private MoveTurnPosMapBlock turnMap;
  487. private AstarManhattan.MWayPoint next_path;
  488. private TimeExpire<int> holdTime;
  489. private bool mPause = true;
  490. private bool mOverrideActionStatus;
  491. private readonly int hold_time;
  492. private readonly int hold_max_time;
  493. private readonly int hold_min_time;
  494. public IPositionObject Target { get; private set; }
  495. public bool IsBypass { get; set; }
  496. public bool IsTurnLR { get { return turnLR != null; } }
  497. public float TargetX { get { return Target.X; } }
  498. public float TargetY { get { return Target.Y; } }
  499. public bool IsNoWay { get; private set; }
  500. public bool IsNoWayAutoFindNear { get; set; }
  501. public MoveAI(InstanceUnit owner, bool overrideActionStatus = true, int holdTimeMS = -1)
  502. {
  503. this.unit = owner;
  504. this.zone = owner.Parent;
  505. this.mOverrideActionStatus = overrideActionStatus;
  506. if (holdTimeMS < 0)
  507. {
  508. hold_time = unit.Templates.CFG.AI_MOVE_AI_HOLD_TIME_MS;
  509. }
  510. else
  511. {
  512. hold_time = holdTimeMS;
  513. }
  514. this.holdTime = new TimeExpire<int>(hold_time);
  515. this.turnLR = new MoveTurnPosObject(unit);
  516. this.turnMap = new MoveTurnPosMapBlock(unit);
  517. this.holdTime.End();
  518. this.hold_max_time = hold_time;
  519. this.hold_min_time = hold_time / 2;
  520. this.IsNoWayAutoFindNear = true;
  521. }
  522. public void Hold(int timeMS = 0)
  523. {
  524. if (timeMS <= 0)
  525. {
  526. timeMS = unit.RandomN.Next(hold_min_time, hold_max_time);
  527. }
  528. holdTime.Reset(timeMS);
  529. }
  530. public void FindPath(float x, float y)
  531. {
  532. this.FindPath(new TMoveTarget(x, y));
  533. }
  534. public void FindPath(IPositionObject target)
  535. {
  536. if (target != null)
  537. {
  538. this.Target = target;
  539. this.next_path = zone.findPath(unit.X, unit.Y, TargetX, TargetY);
  540. if (next_path == null)
  541. {
  542. holdTime.Reset(hold_time);
  543. IsNoWay = true;
  544. var dis = MathVector.getDistance(unit.X, unit.Y, TargetX, TargetY);
  545. //如果不能到达目的地,则找个靠近点
  546. float fixx = -1, fixy = -1;
  547. if (zone.GetNearWay(unit.X, unit.Y, TargetX, TargetY, dis - 1, ref fixx, ref fixy))
  548. {
  549. Target = new TMoveTarget(fixx, fixy);
  550. next_path = zone.findPath(unit.X, unit.Y, TargetX, TargetY);
  551. IsNoWay = next_path == null;
  552. }
  553. }
  554. this.mPause = false;
  555. }
  556. }
  557. public void Pause()
  558. {
  559. this.next_path = null;
  560. this.turnLR.Stop();
  561. this.turnMap.Stop();
  562. this.holdTime.End();
  563. this.mPause = true;
  564. }
  565. public bool IsDirectLookTarget()
  566. {
  567. //if ((Target is InstanceUnit) && CMath.includeRoundPoint(unit.X, unit.Y, unit.Info.GuardRangeLimit, TargetX, TargetY))
  568. if ((Target is InstanceUnit))
  569. {
  570. // 地图连线无阻挡 //
  571. if (!zone.RaycastMap(unit, unit.X, unit.Y, TargetX, TargetY))
  572. {
  573. return true;
  574. }
  575. }
  576. return false;
  577. }
  578. public MoveBlockResult Update()
  579. {
  580. MoveBlockResult result = new MoveBlockResult();
  581. if (Target == null)
  582. {
  583. result.result = MoveResult.MOVE_RESULT_HOLD;
  584. return result;
  585. }
  586. if (mPause)
  587. {
  588. result.result = MoveResult.MOVE_RESULT_HOLD;
  589. return result;
  590. }
  591. else if (IsNoWay)
  592. {
  593. if (IsNoWayAutoFindNear && holdTime.Update(zone.UpdateIntervalMS))
  594. {
  595. this.next_path = zone.findPath(
  596. unit.X,
  597. unit.Y,
  598. TargetX + (float)(unit.Parent.GridCellW * ((unit.Parent.RandomN.NextDouble() * 2) - 1)),
  599. TargetY + (float)(unit.Parent.GridCellH * ((unit.Parent.RandomN.NextDouble() * 2) - 1)));
  600. IsNoWay = next_path == null;
  601. }
  602. //else
  603. //{
  604. // unit.faceTo(Target.X, Target.Y);
  605. // result = unit.moveBlockTo(Target.X, Target.Y, unit.MoveSpeedSEC, zone.UpdateIntervalMS);
  606. // result.result = result.result | MoveResult.MOVE_RESULT_NO_WAY;
  607. // return result;
  608. //}
  609. if (IsNoWay)
  610. {
  611. if (this.unit.IsFollowMaster() && mOverrideActionStatus && unit.CurrentActionStatus != UnitActionStatus.Idle)
  612. {
  613. this.unit.Virtual.SendMsgToClient(CommonAI.XmdsConstConfig.TIPS_FOLLOW_FAIL);
  614. unit.SetActionStatus(UnitActionStatus.Idle);
  615. }
  616. result.result = result.result | MoveResult.MOVE_RESULT_NO_WAY;
  617. return result;
  618. }
  619. }
  620. //if (!holdTime.Update(zone.UpdateIntervalMS))
  621. //{
  622. //result.result = MoveResult.MOVE_RESULT_HOLD;
  623. //if (mOverrideActionStatus) unit.SetActionStatus(UnitActionStatus.Idle);
  624. //}
  625. //else
  626. //{
  627. if (mOverrideActionStatus) unit.SetActionStatus(UnitActionStatus.Move);
  628. if (!turnMap.IsEnd)
  629. {
  630. // 如果向目标移动过程中被地块阻挡,则向左或右调整一段距离 //
  631. if (turnMap.move(unit.MoveSpeedSEC, zone.UpdateIntervalMS, out result))
  632. {
  633. return result;
  634. }
  635. }
  636. else if (!turnLR.IsEnd)
  637. {
  638. // 如果向目标移动过程中被单位阻挡,则向左或右调整一段距离 //
  639. if (turnLR.move(unit.MoveSpeedSEC, zone.UpdateIntervalMS, out result))
  640. {
  641. if ((result.result & MoveResult.MOVE_RESULT_ARRIVED) != 0)
  642. {
  643. result.result ^= MoveResult.MOVE_RESULT_ARRIVED;
  644. }
  645. if ((result.result & MoveResult.MOVE_RESULT_TOUCH_OBJ_GETAWAY) != 0)
  646. {
  647. Hold();
  648. return result;
  649. }
  650. else if ((result.result & MoveResult.MOVE_RESULT_BLOCK_MAP) != 0)
  651. {
  652. Hold();
  653. }
  654. }
  655. }
  656. else if (next_path != null)
  657. {
  658. //if (IsDirectLookTarget())
  659. //{
  660. // next_path = null;
  661. //}
  662. //else
  663. //{
  664. // 如果向目标移动过程中被地图阻挡,则寻路 //
  665. result = unit.moveBlockTo(next_path.PosX, next_path.PosY, unit.MoveSpeedSEC, zone.UpdateIntervalMS);
  666. if ((result.result & MoveResult.MOVE_RESULT_MIN_STEP) != 0 ||
  667. (result.result & MoveResult.MOVE_RESULT_ARRIVED) != 0)
  668. {
  669. }
  670. else
  671. {
  672. unit.faceTo(next_path.PosX, next_path.PosY);
  673. }
  674. if ((result.result & MoveResult.MOVE_RESULT_ARRIVED) != 0)
  675. {
  676. next_path = next_path.Next;
  677. if (next_path != null)
  678. {
  679. result.result ^= MoveResult.MOVE_RESULT_ARRIVED;
  680. if (IsDirectLookTarget())
  681. {
  682. next_path = null;
  683. }
  684. }
  685. else
  686. {
  687. next_path = zone.findPath(unit.X, unit.Y, TargetX, TargetY);
  688. if (next_path == null)
  689. {
  690. Hold();
  691. IsNoWay = true;
  692. }
  693. }
  694. }
  695. else if ((result.result & MoveResult.MOVE_RESULT_TOUCH_MAP_ALL) != 0 && (result.result & MoveResult.MOVE_RESULT_MIN_STEP) != 0)
  696. {
  697. turnMap.Start(next_path.PosX, next_path.PosY);
  698. }
  699. else if ((result.result & MoveResult.MOVE_RESULT_NO_WAY) != 0)
  700. {
  701. next_path = null;
  702. IsNoWay = true;
  703. //unit.faceTo(TargetX, TargetY);
  704. //result = unit.moveBlockTo(TargetX, TargetY, unit.MoveSpeedSEC, zone.UpdateIntervalMS);
  705. }
  706. else if ((result.result & MoveResult.MOVE_RESULT_BLOCK_MAP) != 0)
  707. {
  708. Hold();
  709. next_path = null;
  710. IsNoWay = true;
  711. return result;
  712. }
  713. //}
  714. }
  715. else
  716. {
  717. if (!IsDirectLookTarget())
  718. {
  719. next_path = zone.findPath(unit.X, unit.Y, TargetX, TargetY);
  720. if (next_path == null)
  721. {
  722. Hold();
  723. IsNoWay = true;
  724. }
  725. }
  726. else
  727. {
  728. unit.faceTo(TargetX, TargetY);
  729. result = unit.moveBlockTo(TargetX, TargetY, unit.MoveSpeedSEC, zone.UpdateIntervalMS);
  730. }
  731. }
  732. //}
  733. return result;
  734. }
  735. /// <summary>
  736. /// 如果向目标移动过程中被单位阻挡,则向左或右调整一段距离
  737. /// </summary>
  738. private class MoveTurnPosObject
  739. {
  740. public InstanceUnit Owner { get; private set; }
  741. public InstanceZoneObject Touched { get; private set; }
  742. public bool IsEnd { get; private set; }
  743. public float TargetX { get; private set; }
  744. public float TargetY { get; private set; }
  745. public bool FaceTo { get; private set; }
  746. public int TouchCount { get { return touched_list.Count; } }
  747. private Vector2 TargetPos;
  748. private HashMap<uint, InstanceZoneObject> touched_list = new HashMap<uint, InstanceZoneObject>();
  749. public MoveTurnPosObject(InstanceUnit owner)
  750. {
  751. this.Owner = owner;
  752. this.IsEnd = true;
  753. }
  754. public void Start(float targetX, float targetY, InstanceZoneObject touched)
  755. {
  756. this.Touched = touched;
  757. this.IsEnd = false;
  758. this.TargetPos = new Vector2(targetX, targetY);
  759. this.touched_list.Clear();
  760. TurnNearBypass();
  761. }
  762. public void Stop()
  763. {
  764. this.IsEnd = true;
  765. }
  766. /// <summary>
  767. /// 绕过某个单位移动
  768. /// </summary>
  769. /// <param name="speedSEC"></param>
  770. /// <param name="intervalMS"></param>
  771. /// <param name="result"></param>
  772. /// <returns>是否移动结束</returns>
  773. public bool move(float speedSEC, int intervalMS, out MoveBlockResult result)
  774. {
  775. Owner.faceTo(TargetX, TargetY);
  776. result = Owner.moveBlockTo(TargetX, TargetY, speedSEC, intervalMS);
  777. if (result.obj != null)
  778. {
  779. Touched = result.obj;
  780. }
  781. if ((result.result & (MoveResult.MOVE_RESULT_BLOCK_MAP)) != 0)
  782. {
  783. this.IsEnd = true;
  784. return true;
  785. }
  786. else if ((result.result & (MoveResult.MOVE_RESULT_ARRIVED)) != 0)
  787. {
  788. if (this.TargetX == Owner.X && this.TargetY == Owner.Y)
  789. {
  790. this.TargetX = TargetPos.X;
  791. this.TargetY = TargetPos.Y;
  792. this.IsEnd = true;
  793. return true;
  794. }
  795. }
  796. if (result.obj != null)
  797. {
  798. //换一种躲避方法//
  799. if (touched_list.ContainsKey(result.obj.ID))
  800. {
  801. TurnRandomBypass();
  802. }
  803. else
  804. {
  805. TurnNearBypass();
  806. touched_list.Put(Touched.ID, Touched);
  807. }
  808. }
  809. return false;
  810. }
  811. /// <summary>
  812. /// 获取绕过去,离目标最近的点
  813. /// </summary>
  814. /// <returns></returns>
  815. private Vector2 GetNearTurnPos(InstanceZoneObject obj)
  816. {
  817. float bodysize = Math.Max(Touched.BodyBlockSize, Owner.BodyBlockSize);
  818. float angle = MathVector.getDegree(obj.X - Owner.X, obj.Y - Owner.Y);
  819. Vector2 turnL = new Vector2(Owner.X, Owner.Y);
  820. Vector2 turnR = new Vector2(Owner.X, Owner.Y);
  821. MathVector.movePolar(turnL, angle + CMath.PI_DIV_2, bodysize);
  822. MathVector.movePolar(turnR, angle - CMath.PI_DIV_2, bodysize);
  823. float dl = MathVector.getDistanceSquare(turnL, TargetPos);
  824. float dr = MathVector.getDistanceSquare(turnR, TargetPos);
  825. if (dl < dr)
  826. {
  827. return turnL;
  828. }
  829. else
  830. {
  831. return turnR;
  832. }
  833. }
  834. /// <summary>
  835. /// 碰到障碍时,绕过去
  836. /// </summary>
  837. /// <param name="unit"></param>
  838. private void TurnRandomBypass()
  839. {
  840. float bodysize = (Touched.BodyBlockSize + Owner.BodyBlockSize); // 1~2个身位 //
  841. float distance = bodysize + (float)(Owner.RandomN.NextDouble() * bodysize);
  842. float angle = MathVector.getDegree(Touched.X, Touched.Y, Owner.X, Owner.Y);
  843. float factor = (float)(Owner.RandomN.NextDouble() * (CMath.PI_DIV_2 / 2f));
  844. if (Owner.RandomN.Next(0, 10) % 2 == 0)
  845. {
  846. angle += CMath.PI_DIV_2 - factor;
  847. }
  848. else
  849. {
  850. angle -= CMath.PI_DIV_2 + factor;
  851. }
  852. Vector2 turnLR = new Vector2(Owner.X, Owner.Y);
  853. MathVector.movePolar(turnLR, angle, distance);
  854. this.TargetX = turnLR.X;
  855. this.TargetY = turnLR.Y;
  856. }
  857. /// <summary>
  858. /// 从最近点绕过去
  859. /// </summary>
  860. private void TurnNearBypass()
  861. {
  862. float bodysize = Math.Max(Touched.BodyBlockSize, Owner.BodyBlockSize); // 1~2个身位 //
  863. float distance = bodysize + (float)(Owner.RandomN.NextDouble() * bodysize);
  864. float angle = MathVector.getDegree(Touched.X, Touched.Y, Owner.X, Owner.Y);
  865. Vector2 turnL = new Vector2(Owner.X, Owner.Y);
  866. Vector2 turnR = new Vector2(Owner.X, Owner.Y);
  867. MathVector.movePolar(turnL, angle + CMath.PI_DIV_2, distance);
  868. MathVector.movePolar(turnR, angle - CMath.PI_DIV_2, distance);
  869. float dl = MathVector.getDistanceSquare(turnL, TargetPos);
  870. float dr = MathVector.getDistanceSquare(turnR, TargetPos);
  871. if (dl < dr)
  872. {
  873. this.TargetX = turnL.X;
  874. this.TargetY = turnL.Y;
  875. }
  876. else
  877. {
  878. this.TargetX = turnR.X;
  879. this.TargetY = turnR.Y;
  880. }
  881. }
  882. }
  883. /// <summary>
  884. /// 如果向目标移动过程中被单位阻挡,则向左或右调整一段距离
  885. /// </summary>
  886. private class MoveTurnPosMapBlock
  887. {
  888. public InstanceUnit Owner { get; private set; }
  889. public bool IsEnd { get; private set; }
  890. private float tx;
  891. private float ty;
  892. public MoveTurnPosMapBlock(InstanceUnit owner)
  893. {
  894. this.Owner = owner;
  895. this.IsEnd = true;
  896. }
  897. public void Start(float target_x, float target_y)
  898. {
  899. float tdx = (target_x - Owner.X);
  900. float tdy = (target_y - Owner.Y);
  901. int ddx = (int)CMath.getDirect(tdx);
  902. int ddy = (int)CMath.getDirect(tdy);
  903. if (Math.Abs(tdx) < Math.Abs(tdy))
  904. {
  905. float tw = ddx * (float)(Owner.Parent.GridCellW + (Owner.RandomN.NextDouble() * Owner.Parent.GridCellW / 2f));
  906. tx = Owner.X + tw;
  907. ty = Owner.Y;
  908. }
  909. else
  910. {
  911. float th = ddy * (float)(Owner.Parent.GridCellH + (Owner.RandomN.NextDouble() * Owner.Parent.GridCellH / 2f));
  912. tx = Owner.X;
  913. ty = Owner.Y + th;
  914. }
  915. this.IsEnd = false;
  916. }
  917. public void Stop()
  918. {
  919. this.IsEnd = true;
  920. }
  921. /// <summary>
  922. /// 绕过某个单位移动
  923. /// </summary>
  924. /// <param name="speedSEC"></param>
  925. /// <param name="intervalMS"></param>
  926. /// <param name="result"></param>
  927. /// <returns>是否移动结束</returns>
  928. public bool move(float speedSEC, int intervalMS, out MoveBlockResult result)
  929. {
  930. Owner.faceTo(tx, ty);
  931. MoveImpactResult rst = Owner.moveImpactTo(tx, ty, speedSEC, intervalMS);
  932. result = new MoveBlockResult();
  933. result.result = (MoveResult)((byte)rst);
  934. if ((rst & MoveImpactResult.RESULTS_CAN_NOT_MOVE) != 0)
  935. {
  936. this.IsEnd = true;
  937. return true;
  938. }
  939. return false;
  940. }
  941. }
  942. }
  943. }