using CommonAI.RTS.Manhattan; using CommonAI.Zone.Helper; using CommonLang; using CommonLang.Vector; using System; namespace CommonAI.ZoneClient.Agent { public class ActorMoveAgent : AbstractAgent { public float TargetX { get { return target.X; } } public float TargetY { get { return target.Y; } } public AstarManhattan.FindPathResult Result { get; private set; } private float EndDistance { get; set; } public UnitActionStatus MoveState { get; set; } public object UserData { get; set; } public override bool IsEnd { get { return way_points == null; } } public override bool IsDuplicate { get { return false; } } public bool IsPause { get; set; } public System.Action<float, float, UnitActionStatus> UpdateCheck; private float fSeekDstRadius = 3f; public AstarManhattan.MWayPoint WayPoints { get { return way_points; } } private AstarManhattan.MWayPoint way_points; private Vector2 target; private float cur_dir = 0; private bool auto_adjust = false; private Vector2 cur_pos = new Vector2(); private bool bNeedFixShake = false; public ActorMoveAgent(float toX, float toY, float endDistance, UnitActionStatus st = UnitActionStatus.Move, bool autoAdjust = true, object ud = null, float seekDstRadius = 3.0f) { this.target = new Vector2(toX, toY); this.auto_adjust = autoAdjust; this.EndDistance = endDistance; this.MoveState = st; this.UserData = ud; this.fSeekDstRadius = seekDstRadius; } protected override void OnInit(ZoneActor actor) { this.Owner.OnDoEvent += Owner_OnDoEvent; this.OnEnd += ActorMoveAgent_OnEnd; this.Start(); } private void ActorMoveAgent_OnEnd(AbstractAgent agent) { if (this.Owner != null) { this.Owner.OnDoEvent -= Owner_OnDoEvent; } } protected override void OnDispose() { this.Owner.OnDoEvent -= Owner_OnDoEvent; base.OnDispose(); way_points = null; } public override void Abort() { base.Abort(); Stop(); } private void Owner_OnDoEvent(ZoneObject obj, Zone.ObjectEvent e) { if (e is Zone.UnitForceSyncPosEvent) { this.Abort(); } } //目标移动位置了,重新规则路线 public void RelocateTarget(float x, float y) { target.SetX(x); target.SetY(y); Start(); } /// <summary> /// 再次开始 /// </summary> public void Start() { float distance = MathVector.getDistance(Owner.X, Owner.Y, TargetX, TargetY); if (distance <= EndDistance) { Result = AstarManhattan.FindPathResult.Destination; return; } float destX = TargetX, destY = TargetY; if(Layer.TryTouchMap(Owner, destX, destY)) { way_points = null; Result = AstarManhattan.FindPathResult.NoWay; //目的地不可到达 if (!auto_adjust) { return; } //优化为附近可到达区域 float fixx = -1, fixy = -1; if (!Owner.Parent.GetNearWay(Owner.X, Owner.Y, destX, destY, fSeekDstRadius, ref fixx, ref fixy)) { return; } destX = fixx; destY = fixy; } Result = Owner.Parent.FindPathResult(Owner.X, Owner.Y, destX, destY, out way_points); if (Result == AstarManhattan.FindPathResult.Cross) { if (way_points == null || Layer.TryTouchMap(Owner, way_points.PosX, way_points.PosY)) { Result = AstarManhattan.FindPathResult.NoWay; } else if (way_points != null && way_points.Next != null) { bNeedFixShake = true; } } } /// <summary> /// 外部打断寻路. /// </summary> public void Stop() { this.way_points = null; } static string GetStackTraceModelName() { //当前堆栈信息 System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace(); System.Diagnostics.StackFrame[] sfs = st.GetFrames(); string _filterdName = "ResponseWrite,ResponseWriteError,"; string _fullName = string.Empty, _methodName = string.Empty; for (int i = 1; i < sfs.Length; ++i) { if (System.Diagnostics.StackFrame.OFFSET_UNKNOWN == sfs[i].GetILOffset()) break; _methodName = sfs[i].GetMethod().Name; if (_filterdName.Contains(_methodName)) continue; _fullName = _methodName + "()->" + _fullName; } st = null; sfs = null; _filterdName = _methodName = null; return _fullName.TrimEnd('-', '>'); } private void Turn(int intervalMS) { if (way_points != null) { float direction = MathVector.getDegree(cur_pos.X, cur_pos.Y, way_points.PosX, way_points.PosY); this.cur_dir = MoveHelper.DirectionChange( direction, cur_dir, Owner.TurnSpeedSEC, intervalMS); } } //解决快速连续寻路时,移动方向会一直摇摆的问题 private void fixShake(Vector2 cur, AstarManhattan.MWayPoint head) { if(head.Next != null) { TVector2 nowPos = new TVector2(cur.X, cur.Y); TVector2 vcFirst = new TVector2(head.PosX, head.PosY); TVector2 vcNext = new TVector2(head.Next.PosX, head.Next.PosY); TVector2 v1 = nowPos - vcFirst; TVector2 v2 = vcNext - vcFirst; float a = (float)Math.Atan2(v1.Y, v1.X); float b = (float)Math.Atan2(v2.Y, v2.X); if(float.Equals(a, b) || float.Equals(Math.PI, Math.Abs(a - b))) { //现在的点就是在连线之间,或延长线上 TVector2 v3 = nowPos - vcNext; if (v3.X * v2.X <= 0 && v3.Y * v2.Y <= 0) { //如果当前点在两路点连线之间,就不能朝vcFirst移动了(这样就会倒退,造成摇摆) head.SetPos(nowPos.X, nowPos.Y); } } else { //当前位置不在两个路点的连线上 float dis = nowPos.DistanceTo(vcFirst) * (float)Math.Cos(Math.Abs(a - b)); float dx = (float)(Math.Cos(b) * dis); float dy = (float)(Math.Sin(b) * dis); //如果垂足在两路点连线之外,初始路点不变;如果在连线之间,将寻路起点设为垂足 if (dx * v2.X > 0) { head.SetPos(vcFirst.X + dx, vcFirst.Y + dy); } } } } protected override void BeginUpdate(int intervalMS) { if (way_points == null) { return; } if (IsPause || Owner.CurrentState == UnitActionStatus.Spawn) { return; } if (!Owner.IsCanControlMove) { this.Abort(); return; } cur_pos.SetX(Owner.X); cur_pos.SetY(Owner.Y); cur_dir = Owner.Direction; if (way_points != null) { float disSquare = MathVector.getDistanceSquare(cur_pos.X, cur_pos.Y, TargetX, TargetY); if (disSquare < EndDistance * EndDistance) { this.Stop(); return; } } if (bNeedFixShake) { fixShake(cur_pos, way_points); bNeedFixShake = false; } float length = MoveHelper.GetDistance(intervalMS, Owner.MoveSpeedSEC); float distance = MathVector.getDistance(cur_pos.X, cur_pos.Y, way_points.PosX, way_points.PosY); if (MathVector.moveTo(cur_pos, way_points.PosX, way_points.PosY, length)) { this.way_points = way_points.Next; if (distance < length && way_points != null) { MathVector.moveTo(cur_pos, way_points.PosX, way_points.PosY, length - distance); } } else { Turn(intervalMS); } if (Layer.TryTouchMap(Owner, cur_pos.X, cur_pos.Y)) { this.Abort(); } else { Owner.SendUpdatePos(cur_pos.X, cur_pos.Y, cur_dir, MoveState); if (UpdateCheck != null) { UpdateCheck(TargetX, TargetY, MoveState); } } } public bool TryStep() { if (way_points != null) { float px = Owner.X; float py = Owner.Y; int intervalMS = Layer.CurrentIntervalMS; float length = MoveHelper.GetDistance(intervalMS, Owner.MoveSpeedSEC); float distance = MathVector.getDistance(px, py, way_points.PosX, way_points.PosY); MathVector.moveTo(ref px, ref py, way_points.PosX, way_points.PosY, length); if (Layer.TryTouchMap(Owner, px, py)) { return false; } return true; } return false; } } }