using System; using System.Collections.Generic; using CommonLang.Vector; using CommonLang; using CommonAI.Zone.Instance; using CommonAI.RTS.Manhattan; using CommonLang.IO; namespace CommonAI.Zone.Helper { public class MoveHelper { public static readonly int POS_PRECISION = 255; public static readonly float ToDirectionD8_VALUE = (float)POS_PRECISION /CMath.PI_MUL_2; /// <summary> /// 更新速度 /// </summary> public static void UpdateSpeed(int intervalMS, ref float speedSec, float addSec, float accSec) { float add = 0; float acc = 0; if (addSec != 0) { add = MoveHelper.GetDistance(intervalMS, addSec); } if (accSec != 0) { acc = MoveHelper.GetDistance(intervalMS, speedSec * accSec); } speedSec += (add + acc); } public static void UpdateSpeed(int intervalMS, ref float speedSec, float addSec, float accSec, float speedMin, float speedMax) { float add = 0; float acc = 0; if (addSec != 0) { add = MoveHelper.GetDistance(intervalMS, addSec); } if (accSec != 0) { acc = MoveHelper.GetDistance(intervalMS, speedSec * accSec); } speedSec += (add + acc); if (speedSec > speedMax) { speedSec = speedMax; } if (speedSec < speedMin) { speedSec = speedMin; } } public static void UpdateMoveDistance(int intervalMS, ref float moveDistance, float speed) { moveDistance += MoveHelper.GetDistance(intervalMS, speed); } #region IO public static byte ToDirectionD8(float d) { return (byte)(CMath.OpitimizeRadians(d) * ToDirectionD8_VALUE); } public static float ToDirectionF32(byte d8) { return d8 * CMath.PI_MUL_2 / POS_PRECISION; } public static ushort ToPos16(float x) { return (ushort)(x * POS_PRECISION); } public static float ToPosF32(ushort x) { return ((float)x) / POS_PRECISION; } public static void WritePos(bool half, float x, IOutputStream output) { if (half) { output.PutU16(ToPos16(x)); } else { output.PutF32(x); } } public static void WritePos(bool half, float x, float y, IOutputStream output) { if (half) { output.PutU16(ToPos16(x)); output.PutU16(ToPos16(y)); } else { output.PutF32(x); output.PutF32(y); } } public static void WriteDirection(bool half, float direction, IOutputStream output) { if (half) { output.PutU8(ToDirectionD8(direction)); } else { output.PutF32(direction); } } public static void WritePosAndDirection(bool half, float x, float y, float direction, IOutputStream output) { if (half) { output.PutU16(ToPos16(x)); output.PutU16(ToPos16(y)); output.PutU8(ToDirectionD8(direction)); } else { output.PutF32(x); output.PutF32(y); output.PutF32(direction); } } public static void ReadPos(bool half, out float x, IInputStream input) { if (half) { x = ToPosF32(input.GetU16()); } else { x = input.GetF32(); } } public static void ReadPos(bool half, out float x, out float y, IInputStream input) { if (half) { x = ToPosF32(input.GetU16()); y = ToPosF32(input.GetU16()); } else { x = input.GetF32(); y = input.GetF32(); } } public static void ReadPos(bool half, ref Vector2 pos, IInputStream input) { if (half) { pos.SetX(ToPosF32(input.GetU16())); pos.SetY(ToPosF32(input.GetU16())); } else { pos.SetX(input.GetF32()); pos.SetY(input.GetF32()); } } public static void ReadDirection(bool half, out float direction, IInputStream input) { if (half) { direction = ToDirectionF32(input.GetU8()); } else { direction = input.GetF32(); } } public static void ReadPosAndDirection(bool half, out float x, out float y, out float direction, IInputStream input) { if (half) { x = ToPosF32(input.GetU16()); y = ToPosF32(input.GetU16()); direction = ToDirectionF32(input.GetU8()); } else { x = input.GetF32(); y = input.GetF32(); direction = input.GetF32(); } } #endregion //------------------------------------------------------------------------------------ public static float GetDistance(int timeMS, float speedSEC) { return speedSEC * timeMS / 1000f; } /// <summary> /// 转身算法 /// </summary> /// <param name="dstD">目标角度</param> /// <param name="curD">当前角度</param> /// <param name="turnSpeedSEC">角速度</param> /// <param name="intervalMS">时间间隔</param> /// <returns></returns> public static float DirectionChange(float dstD, float curD, float turnSpeedSEC, int intervalMS) { if (turnSpeedSEC > 0) { float delta = turnSpeedSEC * intervalMS / 1000f; float dd = CMath.OpitimizeRadians(dstD) + CMath.PI_MUL_2; float cd = CMath.OpitimizeRadians(curD) + CMath.PI_MUL_2; float distanceL = Math.Abs(dd - cd); float distanceR = CMath.PI_MUL_2 - distanceL; if (distanceL > distanceR) { if (distanceR <= delta) { return dstD; } if (dd > cd) { curD -= delta; } else { curD += delta; } } else { if (distanceL <= delta) { return dstD; } if (dd > cd) { curD += delta; } else { curD -= delta; } } return curD; } return dstD; } /// <summary> /// 导弹一样飞向目标,并自动调整方向 /// </summary> /// <param name="pos"></param> /// <param name="direction"></param> /// <param name="targetX"></param> /// <param name="targetY"></param> /// <param name="speedSEC"></param> /// <param name="turnSpeedSEC"></param> /// <param name="intervalMS"></param> public static void MoveToTargetTunning(ref Vector2 sPos, ref float direction, float targetX, float targetY, float speedSEC, float turnSpeedSEC, int intervalMS) { float dstD = MathVector.getDegree(targetX - sPos.X, targetY - sPos.Y); direction = DirectionChange(dstD, direction, turnSpeedSEC, intervalMS); MathVector.movePolar(ref sPos, direction, speedSEC, intervalMS); } /// <summary> /// 预估击飞到落下的时间 /// </summary> /// <param name="z">要计算的高度</param> /// <param name="z_speed">Z速度</param> /// <param name="z_limit">Z坐标上限</param> /// <param name="gravity">重力加速度</param> /// <param name="intervalMS">时间精度,越小越精确,一般10足够精度</param> /// <returns></returns> public static int CalculateFlyTimeMS(float z, float z_speed, float z_limit, float gravity, int intervalMS = 10) { int time = 0; float tick_g = GetDistance(intervalMS, gravity); do { time += intervalMS; float sd = GetDistance(intervalMS, z_speed); z += sd; if (z < 0) { time -= (int)Math.Abs(intervalMS * (z / sd)); } if (z_limit != 0 && z_speed > 0 && z > z_limit) { z_speed = 0; } z_speed -= tick_g; } while (z > 0); return time; } /// <summary> /// 给定最大距离和总时间,计算当前抛物线高度 /// y = ax2 + bx + c; /// </summary> /// <param name="maxHeight"></param> /// <param name="totalTimeMS"></param> /// <param name="currentTimeMS"></param> /// <returns></returns> public static float CalulateParabolicHeight(float maxHeight, int totalTimeMS, int currentTimeMS) { float pct = currentTimeMS / (float)totalTimeMS; // 用正弦函数模拟 // float y = (float)(Math.Sin(pct * CMath.PI_F) * maxHeight); return y; } /// <summary> /// 计算单位击退方向 /// </summary> /// <param name="damage">受击者</param> /// <param name="attacker">攻击者</param> /// <param name="mtype"></param> /// <returns></returns> public static float CalculateHitMoveDirection(InstanceUnit damage, InstanceZoneObject attacker, AttackProp.HitMoveType mtype) { switch (mtype) { case AttackProp.HitMoveType.BySenderPosition: return MathVector.getDegree(attacker.X, attacker.Y, damage.X, damage.Y); case AttackProp.HitMoveType.BySenderDirection: return attacker.Direction; case AttackProp.HitMoveType.BySenderLeftRight: float fx = attacker.X; float fy = attacker.Y; MathVector.movePolar(ref fx, ref fy, attacker.Direction, 10); if (CMath.PointOnLine(attacker.X, attacker.Y, fx, fy, damage.X, damage.Y) == CMath.PointOnLineResult.Left) { return attacker.Direction - CMath.PI_DIV_2; } else { return attacker.Direction + CMath.PI_DIV_2; } case AttackProp.HitMoveType.ToSenderCenter: case AttackProp.HitMoveType.ToSenderBodySize: return attacker.Direction + CMath.PI_F; } return damage.Direction + CMath.PI_F; } } public class PopupKeyFrames<K> : IComparer<K> where K : BaseKeyFrame { readonly private List<K> list = new List<K>(); public int Count { get { return list.Count; } } public PopupKeyFrames() { } public void AddRange(ICollection<K> frames) { list.AddRange(frames); list.Sort(this); } /// <summary> /// 取出所有到时间的关键帧 /// </summary> /// <param name="passTimeMS"></param> /// <param name="ret"></param> /// <returns></returns> public int PopKeyFrames(int passTimeMS, List<K> ret = null) { int count = 0; while (list.Count > 0) { int i = list.Count - 1; K kf = list[i]; //不足一帧的,当帧处理 if (kf.FrameMS <= passTimeMS + XmdsConstConfig.GAME_UPDATE_INTERVAL_MS) { list.RemoveAt(i); if (ret != null) { ret.Add(kf); } count++; } else { return count; } } return count; } public int Compare(K x, K y) { return y.FrameMS - x.FrameMS; } } public enum MoveResult : byte { MOVE_SMOOTH = 0, /// <summary> /// 标志状态,本次移动任何方向接触过地图 /// </summary> MOVE_RESULT_TOUCH_MAP_ALL = 0x10, /// <summary> /// 标志状态,阻挡的单位同意让开 /// </summary> MOVE_RESULT_TOUCH_OBJ_GETAWAY = 0x20, /// <summary> /// 标志状态,本次移动等等 /// </summary> MOVE_RESULT_HOLD = 0x40, /// <summary> /// 标志状态,无法移动 /// </summary> MOVE_RESULT_NO_WAY = 0x80, /// <summary> /// 标志判断,到达目标 /// </summary> MOVE_RESULT_ARRIVED = 0x01, /// <summary> /// 标志判断,被单位阻挡 /// </summary> MOVE_RESULT_BLOCK_OBJ = 0x02, /// <summary> /// 标志判断,被地图阻挡 /// </summary> MOVE_RESULT_BLOCK_MAP = 0x04, /// <summary> /// 标志判断,没有达到预期距离或者移动距离太小 /// </summary> MOVE_RESULT_MIN_STEP = 0x08, /// <summary> /// 【标志判断组】,被任何东西阻挡 /// </summary> RESULTS_BLOCK_ANY = MOVE_RESULT_BLOCK_OBJ | MOVE_RESULT_BLOCK_MAP, /// <summary> /// 【标志判断】,移动结束(被阻挡或者到达目标) /// </summary> RESULTS_MOVE_END = MOVE_RESULT_ARRIVED | MOVE_RESULT_BLOCK_OBJ | MOVE_RESULT_BLOCK_MAP | MOVE_RESULT_NO_WAY, } public enum MoveImpactResult : byte { MOVE_SMOOTH = MoveResult.MOVE_SMOOTH, /// <summary> /// 标志状态,本次移动任何方向接触过地图 /// </summary> MOVE_RESULT_TOUCH_MAP = MoveResult.MOVE_RESULT_TOUCH_MAP_ALL, /// <summary> /// 标志状态,阻挡的单位同意让开 /// </summary> MOVE_RESULT_TOUCH_OBJ = MoveResult.MOVE_RESULT_TOUCH_OBJ_GETAWAY, /// <summary> /// 标志判断,被单位阻挡 /// </summary> MOVE_RESULT_BLOCK_OBJ = MoveResult.MOVE_RESULT_BLOCK_OBJ, /// <summary> /// 标志判断,被地图阻挡 /// </summary> MOVE_RESULT_BLOCK_MAP = MoveResult.MOVE_RESULT_BLOCK_MAP, /// <summary> /// 标志判断,没有达到预期距离或者移动距离太小 /// </summary> MOVE_RESULT_MIN_STEP = MoveResult.MOVE_RESULT_MIN_STEP, /// <summary> /// 【标志判断组】,被任何东西阻挡 /// </summary> RESULTS_CAN_NOT_MOVE = MOVE_RESULT_BLOCK_OBJ | MOVE_RESULT_BLOCK_MAP | MOVE_RESULT_MIN_STEP, } public struct MoveBlockResult { public MoveResult result; public InstanceZoneObject obj; public MoveBlockResult(MoveResult r) { this.result = r; this.obj = null; } public bool HasFlag(MoveResult flag) { return (result & flag) != 0; } } public struct TMoveTarget : IPositionObject { private float x; private float y; public TMoveTarget(float x, float y) { this.x = x; this.y = y; } public float X { get { return x; } } public float Y { get { return y; } } public float Direction { get { return 0; } } public float RadiusSize { get { return 0; } } } public class MoveAI { public readonly InstanceUnit unit; public readonly InstanceZone zone; private MoveTurnPosObject turnLR; private MoveTurnPosMapBlock turnMap; private AstarManhattan.MWayPoint next_path; private TimeExpire<int> holdTime; private bool mPause = true; private bool mOverrideActionStatus; private readonly int hold_time; private readonly int hold_max_time; private readonly int hold_min_time; public IPositionObject Target { get; private set; } public bool IsBypass { get; set; } public bool IsTurnLR { get { return turnLR != null; } } public float TargetX { get { return Target.X; } } public float TargetY { get { return Target.Y; } } public bool IsNoWay { get; private set; } public bool IsNoWayAutoFindNear { get; set; } public MoveAI(InstanceUnit owner, bool overrideActionStatus = true, int holdTimeMS = -1) { this.unit = owner; this.zone = owner.Parent; this.mOverrideActionStatus = overrideActionStatus; if (holdTimeMS < 0) { hold_time = unit.Templates.CFG.AI_MOVE_AI_HOLD_TIME_MS; } else { hold_time = holdTimeMS; } this.holdTime = new TimeExpire<int>(hold_time); this.turnLR = new MoveTurnPosObject(unit); this.turnMap = new MoveTurnPosMapBlock(unit); this.holdTime.End(); this.hold_max_time = hold_time; this.hold_min_time = hold_time / 2; this.IsNoWayAutoFindNear = true; } public void Hold(int timeMS = 0) { if (timeMS <= 0) { timeMS = unit.RandomN.Next(hold_min_time, hold_max_time); } holdTime.Reset(timeMS); } public void FindPath(float x, float y) { this.FindPath(new TMoveTarget(x, y)); } public void FindPath(IPositionObject target) { if (target != null) { this.Target = target; this.next_path = zone.findPath(unit.X, unit.Y, TargetX, TargetY); if (next_path == null) { holdTime.Reset(hold_time); IsNoWay = true; var dis = MathVector.getDistance(unit.X, unit.Y, TargetX, TargetY); //如果不能到达目的地,则找个靠近点 float fixx = -1, fixy = -1; if (zone.GetNearWay(unit.X, unit.Y, TargetX, TargetY, dis - 1, ref fixx, ref fixy)) { Target = new TMoveTarget(fixx, fixy); next_path = zone.findPath(unit.X, unit.Y, TargetX, TargetY); IsNoWay = next_path == null; } } this.mPause = false; } } public void Pause() { this.next_path = null; this.turnLR.Stop(); this.turnMap.Stop(); this.holdTime.End(); this.mPause = true; } public bool IsDirectLookTarget() { //if ((Target is InstanceUnit) && CMath.includeRoundPoint(unit.X, unit.Y, unit.Info.GuardRangeLimit, TargetX, TargetY)) if ((Target is InstanceUnit)) { // 地图连线无阻挡 // if (!zone.RaycastMap(unit, unit.X, unit.Y, TargetX, TargetY)) { return true; } } return false; } public MoveBlockResult Update() { MoveBlockResult result = new MoveBlockResult(); if (Target == null) { result.result = MoveResult.MOVE_RESULT_HOLD; return result; } if (mPause) { result.result = MoveResult.MOVE_RESULT_HOLD; return result; } else if (IsNoWay) { if (IsNoWayAutoFindNear && holdTime.Update(zone.UpdateIntervalMS)) { this.next_path = zone.findPath( unit.X, unit.Y, TargetX + (float)(unit.Parent.GridCellW * ((unit.Parent.RandomN.NextDouble() * 2) - 1)), TargetY + (float)(unit.Parent.GridCellH * ((unit.Parent.RandomN.NextDouble() * 2) - 1))); IsNoWay = next_path == null; } //else //{ // unit.faceTo(Target.X, Target.Y); // result = unit.moveBlockTo(Target.X, Target.Y, unit.MoveSpeedSEC, zone.UpdateIntervalMS); // result.result = result.result | MoveResult.MOVE_RESULT_NO_WAY; // return result; //} if (IsNoWay) { if (this.unit.IsFollowMaster() && mOverrideActionStatus && unit.CurrentActionStatus != UnitActionStatus.Idle) { this.unit.Virtual.SendMsgToClient(CommonAI.XmdsConstConfig.TIPS_FOLLOW_FAIL); unit.SetActionStatus(UnitActionStatus.Idle); } result.result = result.result | MoveResult.MOVE_RESULT_NO_WAY; return result; } } //if (!holdTime.Update(zone.UpdateIntervalMS)) //{ //result.result = MoveResult.MOVE_RESULT_HOLD; //if (mOverrideActionStatus) unit.SetActionStatus(UnitActionStatus.Idle); //} //else //{ if (mOverrideActionStatus) unit.SetActionStatus(UnitActionStatus.Move); if (!turnMap.IsEnd) { // 如果向目标移动过程中被地块阻挡,则向左或右调整一段距离 // if (turnMap.move(unit.MoveSpeedSEC, zone.UpdateIntervalMS, out result)) { return result; } } else if (!turnLR.IsEnd) { // 如果向目标移动过程中被单位阻挡,则向左或右调整一段距离 // if (turnLR.move(unit.MoveSpeedSEC, zone.UpdateIntervalMS, out result)) { if ((result.result & MoveResult.MOVE_RESULT_ARRIVED) != 0) { result.result ^= MoveResult.MOVE_RESULT_ARRIVED; } if ((result.result & MoveResult.MOVE_RESULT_TOUCH_OBJ_GETAWAY) != 0) { Hold(); return result; } else if ((result.result & MoveResult.MOVE_RESULT_BLOCK_MAP) != 0) { Hold(); } } } else if (next_path != null) { //if (IsDirectLookTarget()) //{ // next_path = null; //} //else //{ // 如果向目标移动过程中被地图阻挡,则寻路 // result = unit.moveBlockTo(next_path.PosX, next_path.PosY, unit.MoveSpeedSEC, zone.UpdateIntervalMS); if ((result.result & MoveResult.MOVE_RESULT_MIN_STEP) != 0 || (result.result & MoveResult.MOVE_RESULT_ARRIVED) != 0) { } else { unit.faceTo(next_path.PosX, next_path.PosY); } if ((result.result & MoveResult.MOVE_RESULT_ARRIVED) != 0) { next_path = next_path.Next; if (next_path != null) { result.result ^= MoveResult.MOVE_RESULT_ARRIVED; if (IsDirectLookTarget()) { next_path = null; } } else { next_path = zone.findPath(unit.X, unit.Y, TargetX, TargetY); if (next_path == null) { Hold(); IsNoWay = true; } } } else if ((result.result & MoveResult.MOVE_RESULT_TOUCH_MAP_ALL) != 0 && (result.result & MoveResult.MOVE_RESULT_MIN_STEP) != 0) { turnMap.Start(next_path.PosX, next_path.PosY); } else if ((result.result & MoveResult.MOVE_RESULT_NO_WAY) != 0) { next_path = null; IsNoWay = true; //unit.faceTo(TargetX, TargetY); //result = unit.moveBlockTo(TargetX, TargetY, unit.MoveSpeedSEC, zone.UpdateIntervalMS); } else if ((result.result & MoveResult.MOVE_RESULT_BLOCK_MAP) != 0) { Hold(); next_path = null; IsNoWay = true; return result; } //} } else { if (!IsDirectLookTarget()) { next_path = zone.findPath(unit.X, unit.Y, TargetX, TargetY); if (next_path == null) { Hold(); IsNoWay = true; } } else { unit.faceTo(TargetX, TargetY); result = unit.moveBlockTo(TargetX, TargetY, unit.MoveSpeedSEC, zone.UpdateIntervalMS); } } //} return result; } /// <summary> /// 如果向目标移动过程中被单位阻挡,则向左或右调整一段距离 /// </summary> private class MoveTurnPosObject { public InstanceUnit Owner { get; private set; } public InstanceZoneObject Touched { get; private set; } public bool IsEnd { get; private set; } public float TargetX { get; private set; } public float TargetY { get; private set; } public bool FaceTo { get; private set; } public int TouchCount { get { return touched_list.Count; } } private Vector2 TargetPos; private HashMap<uint, InstanceZoneObject> touched_list = new HashMap<uint, InstanceZoneObject>(); public MoveTurnPosObject(InstanceUnit owner) { this.Owner = owner; this.IsEnd = true; } public void Start(float targetX, float targetY, InstanceZoneObject touched) { this.Touched = touched; this.IsEnd = false; this.TargetPos = new Vector2(targetX, targetY); this.touched_list.Clear(); TurnNearBypass(); } public void Stop() { this.IsEnd = true; } /// <summary> /// 绕过某个单位移动 /// </summary> /// <param name="speedSEC"></param> /// <param name="intervalMS"></param> /// <param name="result"></param> /// <returns>是否移动结束</returns> public bool move(float speedSEC, int intervalMS, out MoveBlockResult result) { Owner.faceTo(TargetX, TargetY); result = Owner.moveBlockTo(TargetX, TargetY, speedSEC, intervalMS); if (result.obj != null) { Touched = result.obj; } if ((result.result & (MoveResult.MOVE_RESULT_BLOCK_MAP)) != 0) { this.IsEnd = true; return true; } else if ((result.result & (MoveResult.MOVE_RESULT_ARRIVED)) != 0) { if (this.TargetX == Owner.X && this.TargetY == Owner.Y) { this.TargetX = TargetPos.X; this.TargetY = TargetPos.Y; this.IsEnd = true; return true; } } if (result.obj != null) { //换一种躲避方法// if (touched_list.ContainsKey(result.obj.ID)) { TurnRandomBypass(); } else { TurnNearBypass(); touched_list.Put(Touched.ID, Touched); } } return false; } /// <summary> /// 获取绕过去,离目标最近的点 /// </summary> /// <returns></returns> private Vector2 GetNearTurnPos(InstanceZoneObject obj) { float bodysize = Math.Max(Touched.BodyBlockSize, Owner.BodyBlockSize); float angle = MathVector.getDegree(obj.X - Owner.X, obj.Y - Owner.Y); Vector2 turnL = new Vector2(Owner.X, Owner.Y); Vector2 turnR = new Vector2(Owner.X, Owner.Y); MathVector.movePolar(turnL, angle + CMath.PI_DIV_2, bodysize); MathVector.movePolar(turnR, angle - CMath.PI_DIV_2, bodysize); float dl = MathVector.getDistanceSquare(turnL, TargetPos); float dr = MathVector.getDistanceSquare(turnR, TargetPos); if (dl < dr) { return turnL; } else { return turnR; } } /// <summary> /// 碰到障碍时,绕过去 /// </summary> /// <param name="unit"></param> private void TurnRandomBypass() { float bodysize = (Touched.BodyBlockSize + Owner.BodyBlockSize); // 1~2个身位 // float distance = bodysize + (float)(Owner.RandomN.NextDouble() * bodysize); float angle = MathVector.getDegree(Touched.X, Touched.Y, Owner.X, Owner.Y); float factor = (float)(Owner.RandomN.NextDouble() * (CMath.PI_DIV_2 / 2f)); if (Owner.RandomN.Next(0, 10) % 2 == 0) { angle += CMath.PI_DIV_2 - factor; } else { angle -= CMath.PI_DIV_2 + factor; } Vector2 turnLR = new Vector2(Owner.X, Owner.Y); MathVector.movePolar(turnLR, angle, distance); this.TargetX = turnLR.X; this.TargetY = turnLR.Y; } /// <summary> /// 从最近点绕过去 /// </summary> private void TurnNearBypass() { float bodysize = Math.Max(Touched.BodyBlockSize, Owner.BodyBlockSize); // 1~2个身位 // float distance = bodysize + (float)(Owner.RandomN.NextDouble() * bodysize); float angle = MathVector.getDegree(Touched.X, Touched.Y, Owner.X, Owner.Y); Vector2 turnL = new Vector2(Owner.X, Owner.Y); Vector2 turnR = new Vector2(Owner.X, Owner.Y); MathVector.movePolar(turnL, angle + CMath.PI_DIV_2, distance); MathVector.movePolar(turnR, angle - CMath.PI_DIV_2, distance); float dl = MathVector.getDistanceSquare(turnL, TargetPos); float dr = MathVector.getDistanceSquare(turnR, TargetPos); if (dl < dr) { this.TargetX = turnL.X; this.TargetY = turnL.Y; } else { this.TargetX = turnR.X; this.TargetY = turnR.Y; } } } /// <summary> /// 如果向目标移动过程中被单位阻挡,则向左或右调整一段距离 /// </summary> private class MoveTurnPosMapBlock { public InstanceUnit Owner { get; private set; } public bool IsEnd { get; private set; } private float tx; private float ty; public MoveTurnPosMapBlock(InstanceUnit owner) { this.Owner = owner; this.IsEnd = true; } public void Start(float target_x, float target_y) { float tdx = (target_x - Owner.X); float tdy = (target_y - Owner.Y); int ddx = (int)CMath.getDirect(tdx); int ddy = (int)CMath.getDirect(tdy); if (Math.Abs(tdx) < Math.Abs(tdy)) { float tw = ddx * (float)(Owner.Parent.GridCellW + (Owner.RandomN.NextDouble() * Owner.Parent.GridCellW / 2f)); tx = Owner.X + tw; ty = Owner.Y; } else { float th = ddy * (float)(Owner.Parent.GridCellH + (Owner.RandomN.NextDouble() * Owner.Parent.GridCellH / 2f)); tx = Owner.X; ty = Owner.Y + th; } this.IsEnd = false; } public void Stop() { this.IsEnd = true; } /// <summary> /// 绕过某个单位移动 /// </summary> /// <param name="speedSEC"></param> /// <param name="intervalMS"></param> /// <param name="result"></param> /// <returns>是否移动结束</returns> public bool move(float speedSEC, int intervalMS, out MoveBlockResult result) { Owner.faceTo(tx, ty); MoveImpactResult rst = Owner.moveImpactTo(tx, ty, speedSEC, intervalMS); result = new MoveBlockResult(); result.result = (MoveResult)((byte)rst); if ((rst & MoveImpactResult.RESULTS_CAN_NOT_MOVE) != 0) { this.IsEnd = true; return true; } return false; } } } }