Triggers.View.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using CommonLang;
  5. using CommonAI.RTS;
  6. using CommonLang.Vector;
  7. using CommonAI.RTS.Manhattan;
  8. using CommonAI.Zone.Helper;
  9. namespace CommonAI.Zone.Instance
  10. {
  11. /// <summary>
  12. /// 观察一定范围的触发器
  13. /// </summary>
  14. abstract public class ViewTrigger : Ability
  15. {
  16. /// <summary>
  17. /// 监听单位进出观察范围
  18. /// </summary>
  19. public interface ViewTriggerListener
  20. {
  21. /// <summary>
  22. /// 当一个单位进入观察范围后触发
  23. /// </summary>
  24. /// <param name="src">观察者</param>
  25. /// <param name="obj">进入视野的单位</param>
  26. void onObjectEnterView(ViewTrigger src, InstanceZoneObject obj);
  27. /// <summary>
  28. /// 当一个单位离开观察范围后触发
  29. /// </summary>
  30. /// <param name="src">观察者</param>
  31. /// <param name="obj">离开视野范围的单位</param>
  32. void onObjectLeaveView(ViewTrigger src, InstanceZoneObject obj);
  33. /// <summary>
  34. /// 是否可见
  35. /// </summary>
  36. /// <param name="src"></param>
  37. /// <param name="obj"></param>
  38. /// <returns></returns>
  39. bool select(ViewTrigger src, InstanceZoneObject obj);
  40. }
  41. private bool mEnable = true;
  42. private int mMaxViewd = int.MaxValue;
  43. private ViewTriggerListener mViewListener;
  44. private List<InstanceZoneObject> mViewd = new List<InstanceZoneObject>();
  45. /// <summary>
  46. /// 检测频率
  47. /// </summary>
  48. private readonly TimeInterval<int> mCheckRate;
  49. public bool Enable
  50. {
  51. get { return mEnable; }
  52. set { mEnable = value; }
  53. }
  54. public IEnumerable<InstanceZoneObject> InViewed
  55. {
  56. get { return mViewd; }
  57. }
  58. public ViewTrigger(InstanceZone zone)
  59. : base(zone)
  60. {
  61. mCheckRate = new TimeInterval<int>(Zone.Templates.CFG.AI_VIEW_TRIGGER_CHECK_TIME_MS);
  62. }
  63. public override void Dispose()
  64. {
  65. mEnable = false;
  66. base.Dispose();
  67. mViewd.Clear();
  68. }
  69. public void addViewed(InstanceZoneObject obj)
  70. {
  71. mViewd.Add(obj);
  72. }
  73. public InstanceZoneObject getRandomViewed(Random random)
  74. {
  75. return CUtils.GetRandomInArray<InstanceZoneObject>(mViewd, random);
  76. }
  77. [Obsolete]
  78. public List<InstanceZoneObject> getRandomViewedList(Random random)
  79. {
  80. List<InstanceZoneObject> ret = new List<InstanceZoneObject>(mViewd);
  81. CUtils.RandomList<InstanceZoneObject>(random, ret);
  82. return ret;
  83. }
  84. public void getRandomViewedList(Random random, List<InstanceZoneObject> ret)
  85. {
  86. ret.AddRange(mViewd);
  87. CUtils.RandomList<InstanceZoneObject>(random, ret);
  88. }
  89. /// <summary>
  90. /// 设置最大观察单位数量
  91. /// </summary>
  92. /// <param name="m"></param>
  93. public void setMaxViewd(int m)
  94. {
  95. this.mMaxViewd = m;
  96. }
  97. /// <summary>
  98. /// 增加观察者监听器
  99. /// </summary>
  100. /// <param name="listener"></param>
  101. public void setListener(ViewTriggerListener listener)
  102. {
  103. mViewListener = listener;
  104. }
  105. public virtual void onLookUpdate(float x, float y)
  106. {
  107. if (mEnable)
  108. {
  109. bool is_check = mCheckRate.Update(Zone.UpdateIntervalMS);
  110. this.check(x, y, is_check);
  111. }
  112. else if (mViewd.Count > 0)
  113. {
  114. for (int i = mViewd.Count - 1; i >= 0; --i)
  115. {
  116. onObjectLeaveView(mViewd[i]);
  117. }
  118. mViewd.Clear();
  119. }
  120. }
  121. protected void onObjectEnterView(InstanceZoneObject o)
  122. {
  123. if (mViewListener != null)
  124. {
  125. mViewListener.onObjectEnterView(this, o);
  126. }
  127. }
  128. protected void onObjectLeaveView(InstanceZoneObject o)
  129. {
  130. if (mViewListener != null)
  131. {
  132. mViewListener.onObjectLeaveView(this, o);
  133. }
  134. }
  135. protected virtual void check(float x, float y, bool check)
  136. {
  137. if (check || this.IsNearChanged(x, y))
  138. {
  139. // 检索已看到的消失
  140. for (int i = mViewd.Count - 1; i >= 0; --i)
  141. {
  142. InstanceZoneObject o = mViewd[i];
  143. if (!o.Enable || !mViewListener.select(this, o) || !TestInView(o, x, y))
  144. {
  145. mViewd.RemoveAt(i);
  146. onObjectLeaveView(o);
  147. }
  148. }
  149. this.ForEachNearObjects(x, y, (InstanceZoneObject o) =>
  150. {
  151. if (o.Enable && mViewListener.select(this, o) && !mViewd.Contains(o) && TestInView(o, x, y))
  152. {
  153. mViewd.Add(o);
  154. onObjectEnterView(o);
  155. }
  156. });
  157. }
  158. }
  159. abstract protected bool IsNearChanged(float x, float y);
  160. abstract protected bool TestInView(InstanceZoneObject o, float x, float y);
  161. abstract protected void ForEachNearObjects(float x, float y, Action<InstanceZoneObject> indexer);
  162. }
  163. /// <summary>
  164. /// 瞎子
  165. /// </summary>
  166. public class ViewTriggerBlind : ViewTrigger
  167. {
  168. public ViewTriggerBlind(InstanceZone zone) : base(zone)
  169. {
  170. }
  171. public override void onLookUpdate(float x, float y)
  172. {
  173. }
  174. protected override void ForEachNearObjects(float x, float y, Action<InstanceZoneObject> indexer)
  175. {
  176. }
  177. protected override bool IsNearChanged(float x, float y)
  178. {
  179. return false;
  180. }
  181. protected override bool TestInView(InstanceZoneObject o, float x, float y)
  182. {
  183. return false;
  184. }
  185. }
  186. /// <summary>
  187. /// 观察目标坐标是否在圆形范围内
  188. /// </summary>
  189. public class ViewTriggerRoundCenter : ViewTrigger
  190. {
  191. private float mLookRange;
  192. public ViewTriggerRoundCenter(InstanceZone zone, float r)
  193. : base(zone)
  194. {
  195. this.mLookRange = r;
  196. }
  197. protected override bool IsNearChanged(float x, float y)
  198. {
  199. return Zone.IsNearChanged(x, y, mLookRange);
  200. }
  201. protected override bool TestInView(InstanceZoneObject o, float x, float y)
  202. {
  203. return Collider.Object_Pos_IncludeInRound(o, x, y, mLookRange);
  204. }
  205. protected override void ForEachNearObjects(float x, float y, Action<InstanceZoneObject> indexer)
  206. {
  207. Zone.ForEachNearObjects(x, y, mLookRange, (InstanceZoneObject o, ref bool cancel) =>
  208. {
  209. indexer(o);
  210. });
  211. }
  212. /*
  213. public override void Check(InstanceZone zone, float x, float y, bool check)
  214. {
  215. if (check || zone.IsNearChanged(x, y, mLookRange))
  216. {
  217. // 检索已看到的消失
  218. for (int i = mViewd.Count - 1; i >= 0; --i)
  219. {
  220. InstanceZoneObject o = mViewd[i];
  221. if (!o.Enable || !mViewListener.select(this, o) || !Collider.Object_Pos_IncludeInRound(o, x, y, mLookRange))
  222. {
  223. mViewd.RemoveAt(i);
  224. onObjectLeaveView(o);
  225. }
  226. }
  227. zone.ForEachNearObjects(x, y, mLookRange, (InstanceZoneObject o, ref bool cancel) =>
  228. {
  229. if (o.Enable && mViewListener.select(this, o) && !mViewd.Contains(o) && Collider.Object_Pos_IncludeInRound(o, x, y, mLookRange))
  230. {
  231. mViewd.Add(o);
  232. onObjectEnterView(o);
  233. }
  234. });
  235. }
  236. }
  237. */
  238. }
  239. /// <summary>
  240. /// 观察目标BlockBody是否在圆形范围内
  241. /// </summary>
  242. public class ViewTriggerRoundBody : ViewTrigger
  243. {
  244. private float mLookRange;
  245. public ViewTriggerRoundBody(InstanceZone zone, float r)
  246. : base(zone)
  247. {
  248. this.mLookRange = r;
  249. }
  250. public void SetLookRange(float r)
  251. {
  252. this.mLookRange = r;
  253. }
  254. protected override bool IsNearChanged(float x, float y)
  255. {
  256. return Zone.IsNearChanged(x, y, mLookRange);
  257. }
  258. protected override bool TestInView(InstanceZoneObject o, float x, float y)
  259. {
  260. return Collider.Object_BlockBody_TouchRound(o, x, y, mLookRange);
  261. }
  262. protected override void ForEachNearObjects(float x, float y, Action<InstanceZoneObject> indexer)
  263. {
  264. Zone.ForEachNearObjects(x, y, mLookRange, (InstanceZoneObject o, ref bool cancel) =>
  265. {
  266. indexer(o);
  267. });
  268. }
  269. /*
  270. public override void Check(InstanceZone zone, float x, float y, bool check)
  271. {
  272. if (check || zone.IsNearChanged(x, y, mLookRange))
  273. {
  274. // 检索已看到的消失
  275. for (int i = mViewd.Count - 1; i >= 0; --i)
  276. {
  277. InstanceZoneObject o = mViewd[i];
  278. if (!o.Enable || !mViewListener.select(this, o) || !Collider.Object_BlockBody_TouchRound(o, x, y, mLookRange))
  279. {
  280. mViewd.RemoveAt(i);
  281. onObjectLeaveView(o);
  282. }
  283. }
  284. zone.ForEachNearObjects(x, y, mLookRange, (InstanceZoneObject o, ref bool cancel) =>
  285. {
  286. if (o.Enable && mViewListener.select(this, o) && !mViewd.Contains(o) && Collider.Object_BlockBody_TouchRound(o, x, y, mLookRange))
  287. {
  288. mViewd.Add(o);
  289. onObjectEnterView(o);
  290. }
  291. });
  292. }
  293. }
  294. */
  295. }
  296. /// <summary>
  297. /// 观察目标坐标是否在矩形范围内
  298. /// </summary>
  299. public class ViewTriggerRectCenter : ViewTrigger
  300. {
  301. private float mSizeW;
  302. private float mSizeH;
  303. private float sx, sy, dx, dy;
  304. public ViewTriggerRectCenter(InstanceZone zone, float w, float h)
  305. : base(zone)
  306. {
  307. this.mSizeW = w;
  308. this.mSizeH = h;
  309. }
  310. protected override void check(float x, float y, bool check)
  311. {
  312. this.sx = x - mSizeW / 2;
  313. this.sy = y - mSizeH / 2;
  314. this.dx = sx + mSizeW;
  315. this.dy = sy + mSizeH;
  316. base.check(x, y, check);
  317. }
  318. protected override bool IsNearChanged(float x, float y)
  319. {
  320. return Zone.IsNearChanged(sx, sy, dx, dy);
  321. }
  322. protected override bool TestInView(InstanceZoneObject o, float x, float y)
  323. {
  324. return Collider.Object_Pos_IncludeInRect(o, sx, sy, dx, dy);
  325. }
  326. protected override void ForEachNearObjects(float x, float y, Action<InstanceZoneObject> indexer)
  327. {
  328. Zone.ForEachNearObjectsRect(sx, sy, dx, dy, (InstanceZoneObject o, ref bool cancel) =>
  329. {
  330. indexer(o);
  331. });
  332. }
  333. /*
  334. public override void Check(InstanceZone zone, float x, float y, bool check)
  335. {
  336. if (check || zone.IsNearChanged(x, y, x + mSizeW, y + mSizeH))
  337. {
  338. float sx = x - mSizeW / 2;
  339. float sy = y - mSizeH / 2;
  340. float dx = sx + mSizeW;
  341. float dy = sy + mSizeH;
  342. // 检索已看到的消失
  343. for (int i = mViewd.Count - 1; i >= 0; --i)
  344. {
  345. InstanceZoneObject o = mViewd[i];
  346. if (!o.Enable || !mViewListener.select(this, o) || !Collider.Object_Pos_IncludeInRect(o, sx, sy, dx, dy))
  347. {
  348. mViewd.RemoveAt(i);
  349. onObjectLeaveView(o);
  350. }
  351. }
  352. zone.ForEachNearObjectsRect(sx, sy, dx, dy, (InstanceZoneObject o, ref bool cancel) =>
  353. {
  354. if (o.Enable && mViewListener.select(this, o) && !mViewd.Contains(o) && Collider.Object_Pos_IncludeInRect(o, sx, sy, dx, dy))
  355. {
  356. mViewd.Add(o);
  357. onObjectEnterView(o);
  358. }
  359. });
  360. }
  361. }*/
  362. }
  363. /// <summary>
  364. /// 观察目标坐标是否在矩形范围内
  365. /// </summary>
  366. public class ViewTriggerStripCenter : ViewTrigger
  367. {
  368. private float mWidth;
  369. private float mHigh;
  370. private float mRange;
  371. private float mDirection;
  372. public ViewTriggerStripCenter(InstanceZone zone, float w, float h, float direction)
  373. : base(zone)
  374. {
  375. this.mWidth = w;
  376. this.mHigh = h;
  377. this.mRange = Math.Max(this.mWidth, this.mHigh);
  378. this.mDirection = direction;
  379. }
  380. protected override void check(float x, float y, bool check)
  381. {
  382. base.check(x, y, check);
  383. }
  384. protected override bool IsNearChanged(float x, float y)
  385. {
  386. return Zone.IsNearChanged(x, y, this.mRange);
  387. }
  388. protected override bool TestInView(InstanceZoneObject o, float x, float y)
  389. {
  390. Vector2 p0 = new Vector2(x, y);
  391. Vector2 p1 = new Vector2(x, y);
  392. MathVector.movePolar(p0, this.mDirection, -this.mHigh/2);
  393. MathVector.movePolar(p1, this.mDirection, +this.mHigh/2);
  394. return CMath.includeStripWidthPoint(p0.X, p0.Y, p1.X, p1.Y, this.mWidth, o.X, o.Y);
  395. //return Collider.Object_Pos_IncludeInRect(o, p0.x, p0.y, p1.x, p1.y);
  396. }
  397. protected override void ForEachNearObjects(float x, float y, Action<InstanceZoneObject> indexer)
  398. {
  399. Zone.ForEachNearObjects(x, y, this.mRange, (InstanceZoneObject o, ref bool cancel) =>
  400. {
  401. indexer(o);
  402. });
  403. }
  404. }
  405. /// <summary>
  406. /// 观察目标坐标是否在扇形范围内
  407. /// </summary>
  408. public class ViewTriggerFanCenter : ViewTrigger
  409. {
  410. private float mLookRange;
  411. private float mAngleRange;
  412. private float startAngle, endAngle;
  413. public float Direction { get; set; }
  414. public ViewTriggerFanCenter(InstanceZone zone, float range, float angle)
  415. : base(zone)
  416. {
  417. this.mLookRange = range;
  418. this.mAngleRange = angle;
  419. }
  420. public void SetLookRange(float r)
  421. {
  422. this.mLookRange = r;
  423. }
  424. protected override void check(float x, float y, bool check)
  425. {
  426. this.startAngle = Direction - mAngleRange;
  427. this.endAngle = Direction + mAngleRange;
  428. base.check(x, y, check);
  429. }
  430. protected override bool IsNearChanged(float x, float y)
  431. {
  432. return Zone.IsNearChanged(x, y, mLookRange);
  433. }
  434. protected override bool TestInView(InstanceZoneObject o, float x, float y)
  435. {
  436. return Collider.Object_Pos_IncludeInFan(o, x, y, mLookRange, startAngle, endAngle);
  437. }
  438. protected override void ForEachNearObjects(float x, float y, Action<InstanceZoneObject> indexer)
  439. {
  440. Zone.ForEachNearObjects(x, y, mLookRange, (InstanceZoneObject o, ref bool cancel) =>
  441. {
  442. indexer(o);
  443. });
  444. }
  445. /*
  446. public override void Check(InstanceZone zone, float x, float y, bool check)
  447. {
  448. float startAngle = Direction - mAngleRange;
  449. float endAngle = Direction + mAngleRange;
  450. for (int i = mViewd.Count - 1; i >= 0; --i)
  451. {
  452. InstanceZoneObject o = mViewd[i];
  453. if (!o.Enable || !mViewListener.select(this, o) || !Collider.Object_Pos_IncludeInFan(o, x, y, mLookRange, startAngle, endAngle))
  454. {
  455. mViewd.RemoveAt(i);
  456. onObjectLeaveView(o);
  457. }
  458. }
  459. zone.ForEachNearObjects(x, y, mLookRange, (InstanceZoneObject o, ref bool cancel) =>
  460. {
  461. if (o.Enable && mViewListener.select(this, o) && !mViewd.Contains(o) && Collider.Object_Pos_IncludeInFan(o, x, y, mLookRange, startAngle, endAngle))
  462. {
  463. mViewd.Add(o);
  464. onObjectEnterView(o);
  465. }
  466. });
  467. }*/
  468. }
  469. /// <summary>
  470. /// 观察目标身体是否在扇形范围内
  471. /// </summary>
  472. public class ViewTriggerFanBody : ViewTrigger
  473. {
  474. private float mLookRange;
  475. private float mAngleRange;
  476. private float startAngle, endAngle;
  477. public float Direction { get; set; }
  478. public ViewTriggerFanBody(InstanceZone zone, float range, float angle)
  479. : base(zone)
  480. {
  481. this.mLookRange = range;
  482. this.mAngleRange = angle;
  483. }
  484. public void SetLookRange(float r)
  485. {
  486. this.mLookRange = r;
  487. }
  488. protected override void check(float x, float y, bool check)
  489. {
  490. this.startAngle = Direction - mAngleRange / 2;
  491. this.endAngle = Direction + mAngleRange / 2;
  492. base.check(x, y, check);
  493. }
  494. protected override bool IsNearChanged(float x, float y)
  495. {
  496. return Zone.IsNearChanged(x, y, mLookRange);
  497. }
  498. protected override bool TestInView(InstanceZoneObject o, float x, float y)
  499. {
  500. return Collider.Object_BlockBody_TouchFan(o, x, y, mLookRange, startAngle, endAngle);
  501. }
  502. protected override void ForEachNearObjects(float x, float y, Action<InstanceZoneObject> indexer)
  503. {
  504. Zone.ForEachNearObjects(x, y, mLookRange, (InstanceZoneObject o, ref bool cancel) =>
  505. {
  506. indexer(o);
  507. });
  508. }
  509. /*
  510. public override void Check(InstanceZone zone, float x, float y, bool check)
  511. {
  512. float startAngle = Direction - mAngleRange;
  513. float endAngle = Direction + mAngleRange;
  514. for (int i = mViewd.Count - 1; i >= 0; --i)
  515. {
  516. InstanceZoneObject o = mViewd[i];
  517. if (!o.Enable || !mViewListener.select(this, o) || !Collider.Object_Pos_IncludeInFan(o, x, y, mLookRange, startAngle, endAngle))
  518. {
  519. mViewd.RemoveAt(i);
  520. onObjectLeaveView(o);
  521. }
  522. }
  523. zone.ForEachNearObjects(x, y, mLookRange, (InstanceZoneObject o, ref bool cancel) =>
  524. {
  525. if (o.Enable && mViewListener.select(this, o) && !mViewd.Contains(o) && Collider.Object_Pos_IncludeInFan(o, x, y, mLookRange, startAngle, endAngle))
  526. {
  527. mViewd.Add(o);
  528. onObjectEnterView(o);
  529. }
  530. });
  531. }*/
  532. }
  533. //-------------------------------------------------------------------------------------------
  534. }