AttackRangeHelper.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. using CommonAI.RTS; using CommonLang.Vector;
  2. using CommonAI.Zone.Instance;
  3. using CommonLang;
  4. using CommonLang.Property;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Text;
  9. namespace CommonAI.Zone.Helper
  10. {
  11. public enum AttackShape : byte
  12. {
  13. [DescAttribute("单体")]
  14. Single = 255,
  15. [DescAttribute("圆形")]
  16. Round = 0,
  17. [DescAttribute("扇形")]
  18. Fan = 1,
  19. [DescAttribute("胶囊条状")]
  20. Strip = 2,
  21. [DescAttribute("胶囊射线(以原点出去)")]
  22. StripRay = 3,
  23. [DescAttribute("胶囊射线,接触到最近")]
  24. StripRayTouchEnd = 4,
  25. [DescAttribute("方形条状")]
  26. RectStrip = 12,
  27. [DescAttribute("方形射线(以原点出去)")]
  28. RectStripRay = 13,
  29. [DescAttribute("横向胶囊条状")]
  30. WideStrip = 14,
  31. [DescAttribute("连线类型,比如激光塔持续造成伤害")]
  32. LineToTarget = 5,
  33. [DescAttribute("连线类型,比如伸出去的钩子")]
  34. LineToStart = 7,
  35. [DescAttribute("圆环,中间是空的")]
  36. Circle = 6,
  37. }
  38. public enum AttackReason : byte
  39. {
  40. [Desc("范围攻击或者技能攻击")]
  41. Attack = 0,
  42. [Desc("搜索范围内可攻击目标")]
  43. Look = 1,
  44. [Desc("被攻击后反击")]
  45. Damaged = 2,
  46. [Desc("移动被阻挡后攻击")]
  47. MoveBlocked = 3,
  48. [Desc("检测仇恨目标")]
  49. Tracing = 4,
  50. }
  51. public class AttackRangeHelper
  52. {
  53. private readonly InstanceUnit mLauncherUnit;
  54. private readonly InstanceZone mParent;
  55. private float mCircleInR;
  56. private AttackReason mAttackReason = AttackReason.Attack;
  57. private ITemplateData mWeapon;
  58. public AttackRangeHelper(InstanceUnit launcher)
  59. {
  60. this.mLauncherUnit = launcher;
  61. this.mParent = launcher.Parent;
  62. }
  63. public AttackShape Shape { get; set; }
  64. public SkillTemplate.CastTarget ExpectTarget { get; set; }
  65. public float BodySize { get; set; }
  66. public float FanAngle { get; set; }
  67. public float Direction { get; set; }
  68. public float Distance { get; set; }
  69. public float StripWide { get; set; }
  70. public bool IsHadAttackable(float X, float Y, float r, SpellTemplate spell)
  71. {
  72. var b = mParent.ForEachNearObjects<InstanceUnit>(X, Y, r, (InstanceUnit o, ref bool cancel) =>
  73. {
  74. if (mLauncherUnit.AoiStatus == o.AoiStatus)
  75. {
  76. if (mParent.IsAttackable(mLauncherUnit, o, spell.ExpectTarget, AttackReason.Attack, spell))
  77. {
  78. cancel = true;
  79. }
  80. }
  81. });
  82. return b;
  83. }
  84. /// <summary>
  85. /// 范围伤害,碰撞检测
  86. /// </summary>
  87. /// <param name="list"></param>
  88. /// <param name="reason"></param>
  89. /// <param name="weapon"></param>
  90. /// <param name="X"></param>
  91. /// <param name="Y"></param>
  92. /// <param name="PrevX"></param>
  93. /// <param name="PrevY"></param>
  94. /// <param name="max_affect"></param>
  95. /// <param name="aoi"></param>
  96. /// <returns></returns>
  97. ///
  98. public void GetShapeAttackable(
  99. List<InstanceUnit> list,
  100. AttackReason reason,
  101. ITemplateData weapon,
  102. float X,
  103. float Y,
  104. float PrevX,
  105. float PrevY,
  106. int max_affect,
  107. ObjectAoiStatus aoi)
  108. {
  109. mAttackReason = reason;
  110. mWeapon = weapon;
  111. switch (Shape)
  112. {
  113. case AttackShape.Round:
  114. if (PrevX != X || PrevY != Y)
  115. {
  116. mParent.getObjectsRoundLineRange<InstanceUnit>(touch_RoundLine, PrevX, PrevY, X, Y, BodySize, list, aoi);
  117. }
  118. else
  119. {
  120. mParent.getObjectsRoundRange<InstanceUnit>(touch_Round, X, Y, BodySize, list, aoi);
  121. }
  122. break;
  123. case AttackShape.Circle:
  124. if (BodySize > StripWide)
  125. {
  126. mCircleInR = BodySize - StripWide;
  127. mParent.getObjectsRoundRange<InstanceUnit>(touch_Circle, X, Y, BodySize, list, aoi);
  128. }
  129. else
  130. {
  131. mParent.getObjectsRoundRange<InstanceUnit>(touch_Round, X, Y, BodySize, list, aoi);
  132. }
  133. break;
  134. case AttackShape.Fan:
  135. {
  136. float dfan = FanAngle / 2f;
  137. mParent.getObjectsFanRange<InstanceUnit>(touch_Fan, X, Y, BodySize, Direction - dfan, Direction + dfan, list, aoi);
  138. }
  139. break;
  140. case AttackShape.Strip:
  141. {
  142. //float d_angle = this.Direction + CMath.PI_DIV_2;
  143. float d_width = StripWide / 2f;
  144. float d_distance = Distance / 2f;
  145. Vector2 p0 = new Vector2(X, Y);
  146. Vector2 p1 = new Vector2(X, Y);
  147. MathVector.movePolar(p0, this.Direction, -d_distance);
  148. MathVector.movePolar(p1, this.Direction, d_distance);
  149. mParent.getObjectsRoundLineRange<InstanceUnit>(touch_RoundLine, p0.X, p0.Y, p1.X, p1.Y, d_width, list, aoi);
  150. }
  151. break;
  152. case AttackShape.StripRay:
  153. {
  154. float d_width = StripWide / 2f;
  155. float d_distance = Distance;
  156. Vector2 p1 = new Vector2(X, Y);
  157. MathVector.movePolar(p1, this.Direction, d_distance);
  158. mParent.getObjectsRoundLineRange<InstanceUnit>(touch_RoundLine, X, Y, p1.X, p1.Y, d_width, list, aoi);
  159. }
  160. break;
  161. case AttackShape.StripRayTouchEnd:
  162. {
  163. float d_width = StripWide / 2f;
  164. float d_distance = Distance;
  165. Vector2 p1 = new Vector2(X, Y);
  166. MathVector.movePolar(p1, this.Direction, d_distance);
  167. mParent.getObjectsRoundLineRange<InstanceUnit>(touch_RoundLine, X, Y, p1.X, p1.Y, d_width, list, aoi);
  168. if (list.Count > 1)
  169. {
  170. list.Sort(new ObjectBodySorterNearest<InstanceUnit>(X, Y, d_width));
  171. list.RemoveRange(1, list.Count - 1);
  172. }
  173. }
  174. break;
  175. case AttackShape.RectStrip:
  176. {
  177. //float d_angle = this.Direction + CMath.PI_DIV_2;
  178. float d_width = StripWide / 2f;
  179. float d_distance = Distance / 2f;
  180. Vector2 p0 = new Vector2(X, Y);
  181. Vector2 p1 = new Vector2(X, Y);
  182. MathVector.movePolar(p0, this.Direction, -d_distance);
  183. MathVector.movePolar(p1, this.Direction, d_distance);
  184. mParent.getObjectsRectLineRange<InstanceUnit>(touch_RectLine, p0.X, p0.Y, p1.X, p1.Y, d_width, list, aoi);
  185. }
  186. break;
  187. case AttackShape.RectStripRay:
  188. {
  189. float d_width = StripWide / 2f;
  190. float d_distance = Distance;
  191. Vector2 p1 = new Vector2(X, Y);
  192. MathVector.movePolar(p1, this.Direction, d_distance);
  193. mParent.getObjectsRectLineRange<InstanceUnit>(touch_RectLine, X, Y, p1.X, p1.Y, d_width, list, aoi);
  194. }
  195. break;
  196. case AttackShape.WideStrip:
  197. {
  198. float d_width = StripWide / 2f;
  199. float d_angle = Direction + CMath.PI_DIV_2;
  200. float d_distance = Distance / 2f;
  201. Vector2 p0 = new Vector2(X, Y);
  202. Vector2 p1 = new Vector2(X, Y);
  203. MathVector.movePolar(p0, d_angle, -d_width);
  204. MathVector.movePolar(p1, d_angle, +d_width);
  205. mParent.getObjectsRoundLineRange<InstanceUnit>(touch_RoundLine, p0.X, p0.Y, p1.X, p1.Y, d_distance, list, aoi);
  206. }
  207. break;
  208. case AttackShape.Single:
  209. case AttackShape.LineToTarget:
  210. case AttackShape.LineToStart:
  211. //此类型作为单独命中指定目标//
  212. break;
  213. default:
  214. {
  215. mParent.getObjectsRoundRange<InstanceUnit>(touch_Round, X, Y, BodySize, list, aoi);
  216. }
  217. break;
  218. }
  219. // 最大攻击数量 //
  220. if (max_affect > 0 && list.Count > max_affect)
  221. {
  222. CUtils.RandomList(mParent.RandomN, list);
  223. while (list.Count > max_affect)
  224. {
  225. list.RemoveAt(list.Count - 1);
  226. }
  227. }
  228. }
  229. private bool touch_Round(InstanceZoneObject o, float x, float y, float r)
  230. {
  231. if (CMath.intersectRound(x, y, r, o.X, o.Y, o.BodyHitSize))
  232. {
  233. return mParent.IsAttackable(mLauncherUnit, o as InstanceUnit, ExpectTarget, mAttackReason, mWeapon);
  234. }
  235. return false;
  236. }
  237. private bool touch_Fan(InstanceZoneObject o, float x, float y, float distance, float startAngle, float endAngle)
  238. {
  239. if (CMath.intersectFanRound(x, y, distance, o.X, o.Y, o.BodyHitSize, startAngle, endAngle))
  240. {
  241. return mParent.IsAttackable(mLauncherUnit, o as InstanceUnit, ExpectTarget, mAttackReason, mWeapon);
  242. }
  243. return false;
  244. }
  245. private bool touch_RoundLine(InstanceZoneObject o, float x1, float y1, float x2, float y2, float line_r)
  246. {
  247. if (Collider.Object_HitBody_TouchRoundLine(o, x1, y1, x2, y2, line_r))
  248. {
  249. return mParent.IsAttackable(mLauncherUnit, o as InstanceUnit, ExpectTarget, mAttackReason, mWeapon);
  250. }
  251. return false;
  252. }
  253. private bool touch_RectLine(InstanceZoneObject o, float x1, float y1, float x2, float y2, float line_r)
  254. {
  255. if (Collider.Object_HitBody_TouchRectLine(o, x1, y1, x2, y2, line_r))
  256. {
  257. return mParent.IsAttackable(mLauncherUnit, o as InstanceUnit, ExpectTarget, mAttackReason, mWeapon);
  258. }
  259. return false;
  260. }
  261. private bool touch_Circle(InstanceZoneObject o, float x, float y, float r)
  262. {
  263. if (CMath.intersectRound(x, y, r, o.X, o.Y, o.BodyHitSize))
  264. {
  265. if (mParent.IsAttackable(mLauncherUnit, o as InstanceUnit, ExpectTarget, mAttackReason, mWeapon))
  266. {
  267. if (mCircleInR < o.BodyHitSize)
  268. {
  269. return true;
  270. }
  271. return (!CMath.includeRound2(x, y, mCircleInR, o.X, o.Y, o.BodyHitSize));
  272. }
  273. }
  274. return false;
  275. }
  276. }
  277. }