using CommonAI.RTS; using CommonLang.Vector; using CommonAI.Zone.Instance; using CommonLang; using CommonLang.Property; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace CommonAI.Zone.Helper { public enum AttackShape : byte { [DescAttribute("单体")] Single = 255, [DescAttribute("圆形")] Round = 0, [DescAttribute("扇形")] Fan = 1, [DescAttribute("胶囊条状")] Strip = 2, [DescAttribute("胶囊射线(以原点出去)")] StripRay = 3, [DescAttribute("胶囊射线,接触到最近")] StripRayTouchEnd = 4, [DescAttribute("方形条状")] RectStrip = 12, [DescAttribute("方形射线(以原点出去)")] RectStripRay = 13, [DescAttribute("横向胶囊条状")] WideStrip = 14, [DescAttribute("连线类型,比如激光塔持续造成伤害")] LineToTarget = 5, [DescAttribute("连线类型,比如伸出去的钩子")] LineToStart = 7, [DescAttribute("圆环,中间是空的")] Circle = 6, } public enum AttackReason : byte { [Desc("范围攻击或者技能攻击")] Attack = 0, [Desc("搜索范围内可攻击目标")] Look = 1, [Desc("被攻击后反击")] Damaged = 2, [Desc("移动被阻挡后攻击")] MoveBlocked = 3, [Desc("检测仇恨目标")] Tracing = 4, } public class AttackRangeHelper { private readonly InstanceUnit mLauncherUnit; private readonly InstanceZone mParent; private float mCircleInR; private AttackReason mAttackReason = AttackReason.Attack; private ITemplateData mWeapon; public AttackRangeHelper(InstanceUnit launcher) { this.mLauncherUnit = launcher; this.mParent = launcher.Parent; } public AttackShape Shape { get; set; } public SkillTemplate.CastTarget ExpectTarget { get; set; } public float BodySize { get; set; } public float FanAngle { get; set; } public float Direction { get; set; } public float Distance { get; set; } public float StripWide { get; set; } public bool IsHadAttackable(float X, float Y, float r, SpellTemplate spell) { var b = mParent.ForEachNearObjects(X, Y, r, (InstanceUnit o, ref bool cancel) => { if (mLauncherUnit.AoiStatus == o.AoiStatus) { if (mParent.IsAttackable(mLauncherUnit, o, spell.ExpectTarget, AttackReason.Attack, spell)) { cancel = true; } } }); return b; } /// /// 范围伤害,碰撞检测 /// /// /// /// /// /// /// /// /// /// /// /// public void GetShapeAttackable( List list, AttackReason reason, ITemplateData weapon, float X, float Y, float PrevX, float PrevY, int max_affect, ObjectAoiStatus aoi) { mAttackReason = reason; mWeapon = weapon; switch (Shape) { case AttackShape.Round: if (PrevX != X || PrevY != Y) { mParent.getObjectsRoundLineRange(touch_RoundLine, PrevX, PrevY, X, Y, BodySize, list, aoi); } else { mParent.getObjectsRoundRange(touch_Round, X, Y, BodySize, list, aoi); } break; case AttackShape.Circle: if (BodySize > StripWide) { mCircleInR = BodySize - StripWide; mParent.getObjectsRoundRange(touch_Circle, X, Y, BodySize, list, aoi); } else { mParent.getObjectsRoundRange(touch_Round, X, Y, BodySize, list, aoi); } break; case AttackShape.Fan: { float dfan = FanAngle / 2f; mParent.getObjectsFanRange(touch_Fan, X, Y, BodySize, Direction - dfan, Direction + dfan, list, aoi); } break; case AttackShape.Strip: { //float d_angle = this.Direction + CMath.PI_DIV_2; float d_width = StripWide / 2f; float d_distance = Distance / 2f; Vector2 p0 = new Vector2(X, Y); Vector2 p1 = new Vector2(X, Y); MathVector.movePolar(p0, this.Direction, -d_distance); MathVector.movePolar(p1, this.Direction, d_distance); mParent.getObjectsRoundLineRange(touch_RoundLine, p0.X, p0.Y, p1.X, p1.Y, d_width, list, aoi); } break; case AttackShape.StripRay: { float d_width = StripWide / 2f; float d_distance = Distance; Vector2 p1 = new Vector2(X, Y); MathVector.movePolar(p1, this.Direction, d_distance); mParent.getObjectsRoundLineRange(touch_RoundLine, X, Y, p1.X, p1.Y, d_width, list, aoi); } break; case AttackShape.StripRayTouchEnd: { float d_width = StripWide / 2f; float d_distance = Distance; Vector2 p1 = new Vector2(X, Y); MathVector.movePolar(p1, this.Direction, d_distance); mParent.getObjectsRoundLineRange(touch_RoundLine, X, Y, p1.X, p1.Y, d_width, list, aoi); if (list.Count > 1) { list.Sort(new ObjectBodySorterNearest(X, Y, d_width)); list.RemoveRange(1, list.Count - 1); } } break; case AttackShape.RectStrip: { //float d_angle = this.Direction + CMath.PI_DIV_2; float d_width = StripWide / 2f; float d_distance = Distance / 2f; Vector2 p0 = new Vector2(X, Y); Vector2 p1 = new Vector2(X, Y); MathVector.movePolar(p0, this.Direction, -d_distance); MathVector.movePolar(p1, this.Direction, d_distance); mParent.getObjectsRectLineRange(touch_RectLine, p0.X, p0.Y, p1.X, p1.Y, d_width, list, aoi); } break; case AttackShape.RectStripRay: { float d_width = StripWide / 2f; float d_distance = Distance; Vector2 p1 = new Vector2(X, Y); MathVector.movePolar(p1, this.Direction, d_distance); mParent.getObjectsRectLineRange(touch_RectLine, X, Y, p1.X, p1.Y, d_width, list, aoi); } break; case AttackShape.WideStrip: { float d_width = StripWide / 2f; float d_angle = Direction + CMath.PI_DIV_2; float d_distance = Distance / 2f; Vector2 p0 = new Vector2(X, Y); Vector2 p1 = new Vector2(X, Y); MathVector.movePolar(p0, d_angle, -d_width); MathVector.movePolar(p1, d_angle, +d_width); mParent.getObjectsRoundLineRange(touch_RoundLine, p0.X, p0.Y, p1.X, p1.Y, d_distance, list, aoi); } break; case AttackShape.Single: case AttackShape.LineToTarget: case AttackShape.LineToStart: //此类型作为单独命中指定目标// break; default: { mParent.getObjectsRoundRange(touch_Round, X, Y, BodySize, list, aoi); } break; } // 最大攻击数量 // if (max_affect > 0 && list.Count > max_affect) { CUtils.RandomList(mParent.RandomN, list); while (list.Count > max_affect) { list.RemoveAt(list.Count - 1); } } } private bool touch_Round(InstanceZoneObject o, float x, float y, float r) { if (CMath.intersectRound(x, y, r, o.X, o.Y, o.BodyHitSize)) { return mParent.IsAttackable(mLauncherUnit, o as InstanceUnit, ExpectTarget, mAttackReason, mWeapon); } return false; } private bool touch_Fan(InstanceZoneObject o, float x, float y, float distance, float startAngle, float endAngle) { if (CMath.intersectFanRound(x, y, distance, o.X, o.Y, o.BodyHitSize, startAngle, endAngle)) { return mParent.IsAttackable(mLauncherUnit, o as InstanceUnit, ExpectTarget, mAttackReason, mWeapon); } return false; } private bool touch_RoundLine(InstanceZoneObject o, float x1, float y1, float x2, float y2, float line_r) { if (Collider.Object_HitBody_TouchRoundLine(o, x1, y1, x2, y2, line_r)) { return mParent.IsAttackable(mLauncherUnit, o as InstanceUnit, ExpectTarget, mAttackReason, mWeapon); } return false; } private bool touch_RectLine(InstanceZoneObject o, float x1, float y1, float x2, float y2, float line_r) { if (Collider.Object_HitBody_TouchRectLine(o, x1, y1, x2, y2, line_r)) { return mParent.IsAttackable(mLauncherUnit, o as InstanceUnit, ExpectTarget, mAttackReason, mWeapon); } return false; } private bool touch_Circle(InstanceZoneObject o, float x, float y, float r) { if (CMath.intersectRound(x, y, r, o.X, o.Y, o.BodyHitSize)) { if (mParent.IsAttackable(mLauncherUnit, o as InstanceUnit, ExpectTarget, mAttackReason, mWeapon)) { if (mCircleInR < o.BodyHitSize) { return true; } return (!CMath.includeRound2(x, y, mCircleInR, o.X, o.Y, o.BodyHitSize)); } } return false; } } }