using System;
using System.Collections.Generic;
using System.Text;
using CommonAI.Zone;
using CommonAI.Zone.Instance;
using CommonAI.RTS;
using CommonLang.Vector;
using CommonAI.RTS.Manhattan;
using CommonLang;
using CommonAI.ZoneClient;
using CommonAI.Zone.Helper;
using CommonLang.Concurrent;
using CommonLang.Property;
using CommonLang.Log;
using static CommonAI.Zone.Instance.InstanceUnit;
using CommonAI.Data;

namespace CommonAI.Zone.Instance
{
    //-------------------------------------------------------------------------------------------------------//
    public abstract class InstanceZoneObject : GameEntity, IPositionObject
    {
        protected static readonly Logger log = LoggerFactory.GetDefLogger();
        private static AtomicInteger s_active_object_count = new AtomicInteger(0);
        private static AtomicInteger s_alloc_object_count = new AtomicInteger(0);
        /// <summary>
        /// 活动实例数量
        /// </summary>
        public static int ActiveObjectCount { get { return s_active_object_count.Value; } }
        /// <summary>
        /// 分配实例数量
        /// </summary>
        public static int AllocObjectCount { get { return s_alloc_object_count.Value; } }

        //------------------------------------------------------------------------------------------------

        public TemplateManager Templates { get { return mZone.Templates; } }

        /// <summary>
        /// 获得当前空间分割节点
        /// </summary>
        public SpaceDivision.SpaceCellNode CurrentSpaceCellNode { get { return mCurCellNode.cell; } }

        /// <summary>
        /// 是否为静态阻挡物
        /// </summary>
        readonly public bool IsStaticBlockable;

        private Vector2 mPos = new Vector2();
        readonly private Vector2 mPosPrevFrame = new Vector2();
        private float mPosZPrevFrame = 0;
        private bool mNeedGenSyncPos = true;
        private ObjectForceSyncPosEvent mForceSync = new ObjectForceSyncPosEvent();

        internal readonly InstanceZone mZone;
        internal readonly SpaceDivision.ObjectCellNode mCurCellNode;        // 空间分割节点
        private Random mParentRandom;
        private bool mAdded = false;
        private uint mID = 0;
        private bool mMarkRemoved = false;
        private string mUnitTag = "";
        private ObjectAoiStatus mAoiStatus;

        private bool mIsPause = false;
        private TimeExpire<int> mPauseTime = null;

        private float mDirectionPrevFrame = 0;
        private float mDirection = 0;
        // 此选项表示不影响空间分割,NearChanged属性,不会对ViewTrigger造成影响
        protected bool IsAffectNearChange = true;

        private double mCurPassTimeMS = 0;
        private int mQueryPassTimeMS = 0;
        private ZoneArea mCurrentArea;

        /** 单位是否死亡 */
        public virtual bool IsDead() { return false; }

		public virtual bool IsNeedProcessDead() { return false; }

        //---------------------------------------------------------------------------------------

        public uint ID { get { return mID; } }
        public InstanceZone Parent { get { return mZone; } }
        /// <summary>
        /// 是否已被添加到场景
        /// </summary>
        public bool IsInZone { get { return mAdded; } }
        /// <summary>
        /// 是否未被从场景移除
        /// </summary>
        public bool Enable { get { return !mMarkRemoved; } }
        public float X { get { return mPos.X; } }
        public float Y { get { return mPos.Y; } }
		public float GetX()
		{ 
			return mPos.X;
		}

		public float GetY ()
		{
			return mPos.Y;
		}
		public float Z { get; set; }
        /// <summary>
        /// BodyBlockSize
        /// </summary>
        public float RadiusSize { get { return BodyBlockSize; } }
        /// <summary>
        /// 朝向
        /// </summary>
        virtual public float Direction { get { return mDirection; }  set { mDirection = value; } }
        public Random RandomN { get { return mParentRandom; } }
        /// <summary>
        /// 总共存活了多久
        /// </summary>
        public int PassTimeMS { get { return mQueryPassTimeMS; } }
        /// <summary>
        /// 从编辑器继承过来的参数
        /// </summary>
        public string UnitTag { get { return mUnitTag; } set { this.mUnitTag = value; } }
        /// <summary>
        /// 是否被标记为暂停逻辑
        /// </summary>
        public virtual bool IsPaused { get { return mIsPause; } }

        /// <summary>
        /// IAO标记
        /// </summary>
        public virtual ObjectAoiStatus AoiStatus { get { return mAoiStatus; } }

		/** 获取绑定玩家id */
		public virtual string GetBindPlayerId() { return null; }

        [Desc("获取当前Area")]
        public ZoneArea CurrentArea { get { return mCurrentArea; } }

		public virtual String GetTemplateData() { return ""; }
		//---------------------------------------------------------------------------------------

		public InstanceZoneObject(InstanceZone zone, bool is_static_block)
        {
            s_alloc_object_count++;
            s_active_object_count++;
            this.IsStaticBlockable = is_static_block;
            this.mZone = zone;
            this.mCurCellNode = new SpaceDivision.ObjectCellNode(this);
            this.mParentRandom = mZone.RandomN;
        }
        ~InstanceZoneObject()
        {
            s_alloc_object_count--;
        }
        protected override void Disposing()
        {
            Parent.clearSpace(this);
            this.clearEvents();
            base.Disposing();
            //mCurCellNode = null;
            s_active_object_count--;
        }

        // 返回结果表示当前是否可以添加
        internal bool tryAdd(float x, float y, float direction)
        {
            if (mAdded == false)
            {
                this.mAdded = true;
                this.mMarkRemoved = false;
                this.mID = mZone.genObjectID();
                this.mPos.SetX(x);
                this.mPos.SetY(y);
                this.mPosPrevFrame.SetX(x);
                this.mPosPrevFrame.SetY(y);
                this.mDirection = direction;
                mZone.swapSpace(this, true);
                if (mZone.HasArea) changeArea();
                return true;
            }
            return false;
        }

        // 更新坐标
        internal virtual bool updatePos(InstanceZone zone)
        {
            if (mMarkRemoved) return false;
            bool ret = false;
            if (!mPosPrevFrame.Equals(mPos))
            {
                SpaceDivision.SpaceCellNode old_cell = CurrentSpaceCellNode;
                if (zone.swapSpace(this, IsAffectNearChange))
                {
                    SpaceDivision.SpaceCellNode new_cell = CurrentSpaceCellNode;
                    if (mOnObjectSpaceChanged != null)
                    {
                        mOnObjectSpaceChanged.Invoke(this, old_cell, new_cell);
                    }
                }
                if (mZone.HasArea) changeArea();
                ret = true;
            }
            else if (mDirectionPrevFrame != Direction)
            {
                ret = true;
            }
            else if (mZone.IsSyncZ && mPosZPrevFrame != Z)
            {
                ret = true;
            }
            mPosPrevFrame.SetX(mPos.X);
            mPosPrevFrame.SetY(mPos.Y);
            mPosZPrevFrame = Z;
            mDirectionPrevFrame = Direction;
            mNeedGenSyncPos = ret;
            return ret;
        }

		internal void onAdded(InstanceZone zon, bool pointLv = false)
        {
            if (mOnObjectAdded != null)
            {
                mOnObjectAdded.Invoke(this);
            }
            this.onAdded(pointLv);
        }

        internal void onRemoved(InstanceZone zone)
        {
            this.mAdded = false;
            this.mMarkRemoved = true;
            this.mCurrentArea = null;
            zone.clearSpace(this);
            this.setAoiStatus(null);
            this.onRemoved();
            if (mOnObjectRemoved != null)
            {
                mOnObjectRemoved.Invoke(this);
            }
        }

        // 返回结果表示是否位移
        internal void onUpdate(InstanceZone zone, bool slowRefresh)
        {
            this.onUpdate(slowRefresh);

            if (!IsPaused)
            {
                mCurPassTimeMS += zone.UpdateIntervalMS;
                mQueryPassTimeMS = (int)mCurPassTimeMS;
            }
            else if (mPauseTime != null)
            {
                if (mPauseTime.Update(zone.UpdateIntervalMS))
                {
                    mIsPause = false;
                    mPauseTime = null;
                }
            }
        }

		// 获取队伍的天命属性加成
		public virtual int GetTeamFateValue(UnitFateType fateType)
		{
			return 0;
		}

        internal void onSendingEvent(ref ObjectEvent evt)
        {
            if (mOnObjectSendingEvent != null)
            {
                mOnObjectSendingEvent.Invoke(this, ref evt);
            }
        }

        private void changeArea()
        {
            ZoneArea old_area = mCurrentArea;
            ZoneArea new_area = mZone.GetArea(mPos.X, mPos.Y);
            if (new_area != old_area)
            {
                mCurrentArea = new_area;
                mZone.swapArea(this, old_area, new_area);
                onAreaChanged(old_area, new_area);
                if (mOnObjectAreaChanged != null)
                {
                    mOnObjectAreaChanged.Invoke(this, old_area, new_area);
                }
            }
        }

        protected internal virtual bool GenSyncPos(ref SyncPosEvent.UnitPos ret)
        {
            if (mNeedGenSyncPos)
            {
                ret.SetObject(this);
                return true;
            }
            return false;
        }
        public SyncPosEvent.UnitPos GetSyncPos()
        {
            var ret = new SyncPosEvent.UnitPos();
            ret.SetObject(this);
            return ret;
        }

        //----------------------------------------------------------------------------------------
        /// <summary>
        /// 暂停逻辑
        /// </summary>
        /// <param name="pause"></param>
        /// <param name="timeMS"></param>
        public virtual void Pause(bool pause, int timeMS = 0)
        {
            this.mIsPause = pause;
            if (pause && timeMS > 0)
            {
                this.mPauseTime = new TimeExpire<int>(timeMS);
            }
            else { this.mPauseTime = null; }
        }

        //----------------------------------------------------------------------------------------
        #region DELEGATE

        /// <summary>
        /// 单位添加到场景
        /// </summary>
        /// <param name="obj"></param>
        public delegate void ObjectAddedHandler(InstanceZoneObject obj);
        /// <summary>
        /// 单位被移除触发 
        /// </summary>
        /// <param name="obj"></param>
        public delegate void ObjectRemovedHandler(InstanceZoneObject obj);
        /// <summary>
        /// 单位空间分割区域改变时触发
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="old_node"></param>
        /// <param name="new_node"></param>
        public delegate void ObjectSpaceChangedHandler(InstanceZoneObject obj, SpaceDivision.SpaceCellNode old_node, SpaceDivision.SpaceCellNode new_node);
        /// <summary>
        /// 单位空间分割区域改变时触发
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="old_node"></param>
        /// <param name="new_node"></param>
        public delegate void ObjectAreaChangedHandler(InstanceZoneObject obj, ZoneArea old_node, ZoneArea new_node);
        /// <summary>
        /// 单位发送事件时触发
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="evt"></param>
        public delegate void ObjectSendingEventHandler(InstanceZoneObject obj, ref ObjectEvent evt);

        private ObjectAddedHandler mOnObjectAdded;
        private ObjectRemovedHandler mOnObjectRemoved;
        private ObjectSpaceChangedHandler mOnObjectSpaceChanged;
        private ObjectAreaChangedHandler mOnObjectAreaChanged;
        private ObjectSendingEventHandler mOnObjectSendingEvent;

        public event ObjectAddedHandler OnObjectAdded { add { mOnObjectAdded += value; } remove { mOnObjectAdded -= value; } }
        public event ObjectRemovedHandler OnObjectRemoved { add { mOnObjectRemoved += value; } remove { mOnObjectRemoved -= value; } }
        public event ObjectSpaceChangedHandler OnObjectSpaceChanged { add { mOnObjectSpaceChanged += value; } remove { mOnObjectSpaceChanged -= value; } }
        public event ObjectAreaChangedHandler OnObjectAreaChanged { add { mOnObjectAreaChanged += value; } remove { mOnObjectAreaChanged -= value; } }
        public event ObjectSendingEventHandler OnObjectSendingEvent { add { mOnObjectSendingEvent += value; } remove { mOnObjectSendingEvent -= value; } }

        protected virtual void clearEvents()
        {
            mOnObjectAdded = null;
            mOnObjectRemoved = null;
            mOnObjectSpaceChanged = null;
            mOnObjectAreaChanged = null;
            mOnObjectSendingEvent = null;
        }
        #endregion
        //---------------------------------------------------------------------------------------------------------
        #region ABSTRACT

        /// <summary>
        /// 地图阻挡 ?
        /// </summary>
        abstract public bool IntersectMap { get; }
        /// <summary>
        /// 单位阻挡
        /// </summary>
        abstract public bool IntersectObj { get; }

        /// <summary>
        /// 是否可以动
        /// </summary>
        abstract public bool Moveable { get; }

        /// <summary>
        /// 自身体积(半径)
        /// </summary>
        abstract public float BodyBlockSize { get; }
        /// <summary>
        /// 受击半径
        /// </summary>
        abstract public float BodyHitSize { get; }
        /// <summary>
        /// 身体高度
        /// </summary>
        abstract public float BodyHeight { get; }
        /// <summary>
        /// 是否同步客户端
        /// </summary>
        abstract public bool ClientVisible { get; }

        abstract public float Weight { get; }

        /// <summary>
        /// 是否允许帧同步
        /// </summary>
        abstract public bool SyncPos { get; }

        abstract protected void onUpdate(bool slowRefresh);

        abstract protected void onAdded(bool pointLv);
        abstract protected void onRemoved();

        /*
        /// <summary>
        /// 被攻击到
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="attack"></param>
        /// <returns></returns>
        virtual internal bool onHitAttack(InstanceUnit sender, AttackProp attack) { return false; }
        */
        /// <summary>
        /// 获取同步信息
        /// </summary>
        abstract public SyncObjectInfo GenSyncInfo(bool network);

        #endregion
        //---------------------------------------------------------------------------------------
        /// <summary>
        /// 直接转向
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        public virtual void faceTo(float x, float y)
        {
            if (mPos.X == x && mPos.Y == y)
            {
                return;
            }
            this.faceTo((float)(Math.Atan2(y - mPos.Y, x - mPos.X)));
        }
        /// <summary>
        /// 直接转向
        /// </summary>
        /// <param name="d"></param>
        public virtual void faceTo(float d)
        {
            this.mDirection = d;
        }
        /// <summary>
        /// 基于当前角度转向
        /// </summary>
        /// <param name="add"></param>
        public virtual void turn(float add)
        {
            this.mDirection += add;
        }

        public bool setPos(float x, float y, bool touchMap = false)
        {
            if (touchMap)
            {
                if (!mZone.TryTouchMap(this, x, y))
                {
                    this.mPos.SetX(x);
                    this.mPos.SetY(y);
                    Parent.swapSpace(this, true);
                    return true;
                }
                return false;
            }
            else
            {
                this.mPos.SetX(x);
                this.mPos.SetY(y);
                Parent.swapSpace(this, true);
                return true;
            }
        }
        public bool setPos(float x, float y, float z, bool touchMap = false)
        {
            if (touchMap)
            {
                if (!mZone.TryTouchMap(this, x, y))
                {
                    this.mPos.SetX(x);
                    this.mPos.SetY(y);
                    this.Z = z;
                    Parent.swapSpace(this, true);
                    return true;
                }
                return false;
            }
            else
            {
                this.mPos.SetX(x);
                this.mPos.SetY(y);
                this.Z = z;
                Parent.swapSpace(this, true);
                return true;
            }
        }

        public void setAoiStatus(ObjectAoiStatus aoi)
        {
            if (this.mAoiStatus != aoi)
            {
                if (this.mAoiStatus != null)
                {                    
					try
					{
						if(mAoiStatus !=null && mAoiStatus.IsNeedNotifyClient && this is InstancePlayer)
						{
							var ce = new ChatEvent(ChatMessageType.SystemToPlayer);
							ce.ToPlayerUUID = (this as InstancePlayer).PlayerUUID;
							ce.Message = "LeaveAOI";
							this.Parent.queueEvent(ce);
						}

						this.mAoiStatus.RemoveObject(this);
					}
					catch(Exception e)
					{
						log.Warn("setAoiStatus catch: " + this.Parent.GetSceneID() + ", " + (mAoiStatus == null ? "aoi null" : mAoiStatus.ToString()) + ", " + 
							this.GetTemplateData() + ", setaoI:" + (aoi == null ? "aoi null" :  aoi.ToString()) + ", " + e);
					}                   
                }
                this.mAoiStatus = aoi;
                if (this.mAoiStatus != null)
                {
                    this.mAoiStatus.AddObject(this);
                    if (this is InstancePlayer && mAoiStatus.IsNeedNotifyClient)
                    {
                        var ce = new ChatEvent(ChatMessageType.SystemToPlayer);
                        ce.ToPlayerUUID = (this as InstancePlayer).PlayerUUID;
                        ce.Message = "EnterAOI";
                        this.Parent.queueEvent(ce);
                    }
                }

				InstancePlayer player = this as InstancePlayer;
				if(player != null)
				{
					//玩家停止技能行为
					StateSkill state = player.CurrentState as StateSkill;
					if (state != null)
					{
						PlayerSkillStopEvent evt = new PlayerSkillStopEvent(player.ID, state.SkillData.ID);
						player.queueEvent(evt);
						state.Skill.ForceIntoCD();
						player.changeState(new StateIdle(player), true);
					}
				}				
			}
        }

        public virtual void SendForceSync()
        {
            mForceSync.object_id = this.ID;
            mForceSync.X = this.X;
            mForceSync.Y = this.Y;
            mForceSync.Direction = this.Direction;
            Parent.queueObjectEvent(this, mForceSync);
        }

        //---------------------------------------------------------------------------------------------------------



        protected virtual void onAreaChanged(ZoneArea old_area, ZoneArea new_area) { }

        /// <summary>
        /// 在移动时被某个单位阻挡
        /// </summary>
        /// <param name="obj"></param>
        protected virtual void onMoveBlockWithObject(InstanceZoneObject obj) { }

        /// <summary>
        /// 阻挡到其他单位移动
        /// </summary>
        /// <param name="obj"></param>
        /// <returns >通知其他单位自己可以让开</returns>
        protected virtual bool onBlockOther(InstanceZoneObject obj) { return false; }

        //---------------------------------------------------------------------------------------------------------
        /// <summary>
        /// 无碰撞移动
        /// </summary>
        /// <param name="direction"></param>
        /// <param name="speedSEC"></param>
        /// <param name="intervalMS"></param>
        public void flyTo(float direction, float speedSEC, int intervalMS)
        {
            float distance = MoveHelper.GetDistance(intervalMS, speedSEC);
            MathVector.movePolar(mPos, direction, distance);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="speedSEC"></param>
        /// <param name="intervalMS"></param>
        /// <returns>是否到达终点</returns>
        public bool flyToTarget(float x, float y, float speedSEC, int intervalMS)
        {
            float distance = MoveHelper.GetDistance(intervalMS, speedSEC);
            return MathVector.moveTo(mPos, x, y, distance);
        }
        public void flyToTargetTunning(float x, float y, float speedSEC, float tunningSpeedSEC, int intervalMS)
        {
            MoveHelper.MoveToTargetTunning(ref mPos, ref mDirection, x, y, speedSEC, tunningSpeedSEC, intervalMS);
        }


		//曲线移动
		public void CurveMoveTo(Vector2 startPos, Vector2 handlePos, float endX, float endY, float fStep, float speedSEC, int intervalMS)
		{
			//float pX1 = startPos.X * (1 - fStep) + handlePos.X * fStep;
			//float pY1 = startPos.Y * (1 - fStep) + handlePos.Y * fStep;
			//float pX2 = 
			//Vector3 result = (1 - fStep) * p0p1 + fStep * p1p2;
		}


        /// <summary>
        /// 越过单位跳跃
        /// </summary>
        /// <param name="direction"></param>
        /// <param name="speedSEC"></param>
        /// <param name="intervalMS"></param>
        /// <param name="ignore_z"></param>
        /// <returns>是否到达终点</returns>
        public bool jumpTo(float direction, float speedSEC, int intervalMS, bool ignore_z = true)
        {
            float distance = MoveHelper.GetDistance(intervalMS, speedSEC);
            float dx = (float)(Math.Cos(direction) * distance);
            float dy = (float)(Math.Sin(direction) * distance);
            if (IntersectMap)
            {
                float oldx = mPos.X;
                float oldy = mPos.Y;
                switch (Parent.TryMoveToMapBorder(this, ref mPos, dx, dy))
                {
                    case AstarManhattan.TryMoveToMapBorderResult.BLOCK:
                        return true;
                }
                if (ignore_z)
                {
                    if (mZone.intersectNearStaticBlockable(this) != null)
                    {
                        mPos.SetY(oldy);
                        mPos.SetX(oldx);
                        return true;
                    }
                }
                else
                {
                    if (mZone.intersectNearStaticBlockableZ(this) != null)
                    {
                        mPos.SetY(oldy);
                        mPos.SetX(oldx);
                        return true;
                    }
                }
            }
            else
            {
                this.mPos.AddX(dx);
                this.mPos.AddY(dy);
            }
            return false;
        }
        public bool jumpToTarget(float x, float y, float speedSEC, int intervalMS, bool ignore_z = true)
        {
            float distance = MoveHelper.GetDistance(intervalMS, speedSEC);
            float ddx = x - mPos.X;
            float ddy = y - mPos.Y;
            float direction = MathVector.getDegree(ddx, ddy);
            float dx = (float)(Math.Cos(direction) * distance);
            float dy = (float)(Math.Sin(direction) * distance);
            bool minstep = false;
            if (Math.Abs(ddx) < distance && Math.Abs(ddy) < distance)
            {
                dx = ddx;
                dy = ddy;
                minstep = true;
            }
            if (IntersectMap)
            {
                float oldx = mPos.X;
                float oldy = mPos.Y;
                switch (Parent.TryMoveToMapBorder(this, ref mPos, dx, dy))
                {
                    case AstarManhattan.TryMoveToMapBorderResult.BLOCK:
                        if (IntersectObj) ElasticOtherObjects();
                        return true;
                }
                if (ignore_z)
                {
                    if (mZone.intersectNearStaticBlockable(this) != null)
                    {
                        mPos.SetY(oldy);
                        mPos.SetX(oldx);
                        if (IntersectObj) ElasticOtherObjects();
                        return true;
                    }
                }
                else
                {
                    if (mZone.intersectNearStaticBlockableZ(this) != null)
                    {
                        mPos.SetY(oldy);
                        mPos.SetX(oldx);
                        if (IntersectObj) ElasticOtherObjects();
                        return true;
                    }
                }
            }
            else
            {
                this.mPos.AddX(dx);
                this.mPos.AddY(dy);
            }
            return minstep;
        }

        //---------------------------------------------------------------------------------------------------------

        //---------------------------------------------------------------------------------------------------------
        /// <summary>
        /// 移动到目标点
        /// </summary>
        /// <param name="angle"></param>
        /// <param name="speedSEC"></param>
        /// <param name="intervalMS"></param>
        /// <returns>可以顺利移动</returns>
        public MoveBlockResult moveBlockTo(float angle, float speedSEC, int intervalMS)
        {
            float dd = MoveHelper.GetDistance(intervalMS, speedSEC);
            float dx = (float)(Math.Cos(angle) * dd);
            float dy = (float)(Math.Sin(angle) * dd);
            return moveBlock(dx, dy);
        }

        /// <summary>
        /// 移动到目标点
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="speedSEC"></param>
        /// <param name="intervalMS"></param>
        /// <returns>可以顺利移动</returns>
        public MoveBlockResult moveBlockTo(float x, float y, float speedSEC, int intervalMS)
        {
            if (mPos.X == x && mPos.Y == y)
            {
                MoveBlockResult result = new MoveBlockResult(MoveResult.MOVE_RESULT_ARRIVED);
                return result;
            }
            float distance = MoveHelper.GetDistance(intervalMS, speedSEC);
            float ddx = x - mPos.X;
            float ddy = y - mPos.Y;
            if (Math.Abs(ddx) < distance && Math.Abs(ddy) < distance)
            {
                MoveBlockResult result = moveBlock(ddx, ddy);
                if ((result.result & MoveResult.RESULTS_MOVE_END) != 0)
                {

                }
                else
                {
                    result.result |= MoveResult.MOVE_RESULT_ARRIVED;
                }
                return result;
            }
            else
            {
                float oldx = mPos.X;
                float oldy = mPos.Y;
                float direction = (float)(Math.Atan2(ddy, ddx));
                float dx = (float)(Math.Cos(direction) * distance);
                float dy = (float)(Math.Sin(direction) * distance);
                MoveBlockResult result = moveBlock(dx, dy);
                ddx = Math.Abs(mPos.X - oldx);
                ddy = Math.Abs(mPos.Y - oldy);
                float minstep = Parent.MinStep;
                if (ddx < minstep && ddy < minstep)
                {
                    result.result |= MoveResult.MOVE_RESULT_MIN_STEP;
                }
                return result;
            }

        }

        /// <summary>
        /// 尝试碰撞移动偏移量
        /// </summary>
        /// <param name="dx"></param>
        /// <param name="dy"></param>
        /// <returns></returns>
        public MoveBlockResult moveBlock(float dx, float dy)
        {
            float oldx = mPos.X;
            float oldy = mPos.Y;
            MoveBlockResult result = new MoveBlockResult(0);
            if (IntersectMap)
            {
                //尝试地图碰撞移动//
                var res = Parent.TryMoveToMapBorder(this, ref mPos, dx, dy);
                switch (res)
                {
                    case AstarManhattan.TryMoveToMapBorderResult.BLOCK:
                        result.result |= MoveResult.MOVE_RESULT_TOUCH_MAP_ALL;
                        result.result |= MoveResult.MOVE_RESULT_BLOCK_MAP;
                        return result;
                    case AstarManhattan.TryMoveToMapBorderResult.TOUCH:
                        result.result |= MoveResult.MOVE_RESULT_TOUCH_MAP_ALL;
                        break;
                    case AstarManhattan.TryMoveToMapBorderResult.ARRIVE:
                        break;
                }
                //和建筑碰撞//
                if (this.IntersectObj)
                {
                    InstanceZoneObject bu = mZone.intersectNearStaticBlockable(this);
                    result.obj = bu;
                    if (bu != null)
                    {
                        mPos.SetY(oldy);
                        mPos.SetX(oldx);
                        result.result |= MoveResult.MOVE_RESULT_BLOCK_OBJ;
                        //恢复到原来位置也碰撞的话,就弹开//
                        if (mZone.TouchObject2(this, bu))
                        {
                            ElasticOtherObject(bu);
                        }
                        onMoveBlockWithObject(bu);
                    }
                    return result;
                }
            }
            else
            {
                this.mPos.AddX(dx);
                this.mPos.AddY(dy);
            }
            if (this.IntersectObj)
            {
                //和单位碰撞//
                InstanceZoneObject bu = mZone.intersectNearUnit(this);
                result.obj = bu;
                if (bu != null)
                {
                    mPos.SetY(oldy);
                    mPos.SetX(oldx);
                    if (bu.onBlockOther(this))
                    {
                        result.result |= MoveResult.MOVE_RESULT_TOUCH_OBJ_GETAWAY;
                    }
                    result.result |= MoveResult.MOVE_RESULT_BLOCK_OBJ;
                    if (mZone.TouchObject2(this, bu))
                    {
                        //恢复到原来位置也碰撞的话,就弹开//
                        if (ElasticOtherObject(bu) == false)
                        {
                            this.mPos.AddX(dx);
                            this.mPos.AddY(dy);
                        }
                    }
                    onMoveBlockWithObject(bu);
                }
            }
            return result;
        }


        /// <summary>
        /// 挤开对方的移动方式
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="speedSEC"></param>
        /// <param name="intervalMS"></param>
        /// <returns>TRUE=无法移动</returns>
        public MoveImpactResult moveImpactTo(float x, float y, float speedSEC, int intervalMS)
        {
            float minstep = Parent.MinStep;
            float distance = MoveHelper.GetDistance(intervalMS, speedSEC);
            if (Math.Abs(distance) < minstep)
            {
                return MoveImpactResult.MOVE_RESULT_MIN_STEP;
            }
            float ddx = x - mPos.X;
            float ddy = y - mPos.Y;
            if (Math.Abs(ddx) < distance && Math.Abs(ddy) < distance)
            {
                return MoveImpactResult.MOVE_RESULT_MIN_STEP;
            }
            float angle = MathVector.getDegree(ddx, ddy);
            return moveImpactInner(angle, distance, 0);
        }

        /// <summary>
        /// 挤开对方的移动方式
        /// </summary>
        /// <param name="angle"></param>
        /// <param name="speedSEC"></param>
        /// <param name="intervalMS"></param>
        /// <returns>TRUE=无法移动</returns>
        public MoveImpactResult moveImpact(float angle, float speedSEC, int intervalMS)
        {
            float minstep = Parent.MinStep;
            float distance = MoveHelper.GetDistance(intervalMS, speedSEC);
            if (Math.Abs(distance) < minstep)
            {
                return MoveImpactResult.MOVE_RESULT_MIN_STEP;
            }
            return moveImpactInner(angle, distance, 0);
        }
        public MoveImpactResult moveImpactDistance(float angle, float distance)
        {
            float minstep = Parent.MinStep;
            if (Math.Abs(distance) < minstep)
            {
                return MoveImpactResult.MOVE_RESULT_MIN_STEP;
            }
            return moveImpactInner(angle, distance, 0);
        }
        protected virtual MoveImpactResult moveImpactInner(float angle, float distance, int depth)
        {
            MoveImpactResult ret = MoveImpactResult.MOVE_SMOOTH;
            float dx = (float)(Math.Cos(angle) * distance);
            float dy = (float)(Math.Sin(angle) * distance);
            float oldx = mPos.X;
            float oldy = mPos.Y;
            if (IntersectMap)
            {
                switch (Parent.TryMoveToMapBorder(this, ref mPos, dx, dy))
                {
                    case AstarManhattan.TryMoveToMapBorderResult.BLOCK:
                        ret |= MoveImpactResult.MOVE_RESULT_BLOCK_MAP;
                        ret |= MoveImpactResult.MOVE_RESULT_TOUCH_MAP;
                        return ret;
                    case AstarManhattan.TryMoveToMapBorderResult.TOUCH:
                        ret |= MoveImpactResult.MOVE_RESULT_TOUCH_MAP;
                        break;
                    case AstarManhattan.TryMoveToMapBorderResult.ARRIVE:
                        break;
                }
            }
            else
            {
                this.mPos.AddX(dx);
                this.mPos.AddY(dy);
            }
            if (!this.IntersectObj)
            {
                if (IntersectMap)
                {
                    InstanceZoneObject bu = mZone.intersectNearStaticBlockable(this);
                    if (bu != null)
                    {
                        mPos.SetY(oldy);
                        mPos.SetX(oldx);
                        ret |= MoveImpactResult.MOVE_RESULT_BLOCK_OBJ;
                        ret |= MoveImpactResult.MOVE_RESULT_TOUCH_OBJ;
                        return ret;
                    }
                }
                return ret;
            }
            else
            {
                uint max_depth = Templates.CFG.GLOBAL_MOVE_IMPACT_DEPTH;
                bool touched = Parent.ForEachNearObjects(mPos.X, mPos.Y, (InstanceZoneObject o, ref bool cancel) =>
                {
                    if (o != this && o.IntersectObj && Parent.TouchObject2(this, o))
                    {
                        ret |= MoveImpactResult.MOVE_RESULT_TOUCH_OBJ;
                        if ((!o.IsStaticBlockable) && (o.Weight <= this.Weight))
                        {
                            if (depth < max_depth)
                            {
                                float targetAngle = MathVector.getDegree(this.X, this.Y, o.X, o.Y);
                                float ddr = MathVector.getDistance(o.mPos, this.mPos);
                                float bdr = (this.BodyBlockSize + o.BodyBlockSize);
                                o.moveImpactInner(targetAngle, (bdr - ddr), depth + 1);
                            }
                            else
                            {
                                this.mPos.SetX(oldx);
                                this.mPos.SetY(oldy);
                                cancel = true;
                                ret |= MoveImpactResult.MOVE_RESULT_BLOCK_OBJ;
                            }
                        }
                        else
                        {
                            this.mPos.SetX(oldx);
                            this.mPos.SetY(oldy);
                            cancel = true;
                            ret |= MoveImpactResult.MOVE_RESULT_BLOCK_OBJ;
                            if (Parent.TouchObject2(this, o))
                            {
                                float targetAngle = MathVector.getDegree(o.X, o.Y, this.X, this.Y);
                                float ddr = MathVector.getDistance(o.mPos, this.mPos);
                                float bdr = (this.BodyBlockSize + o.BodyBlockSize);
                                //强制将自己移动到某处//
                                this.moveLinearMap((bdr - ddr), targetAngle);
                            }
                        }
                    }
                });
                return ret;
            }
        }

        //-------------------------------------------------------------------------------------------------------//

        /// <summary>
        /// 线性移动,只和地图碰撞
        /// </summary>
        /// <param name="distance"></param>
        /// <param name="angle"></param>
        /// <returns>和地图碰撞</returns>
        public bool moveLinearMap(float distance, float angle)
        {
            float dx = (float)(Math.Cos(angle) * distance);
            float dy = (float)(Math.Sin(angle) * distance);
            float touch_x, touch_y, touch_d;
            if (Parent.PathFinder.GetLineTouchPoint(mPos.X, mPos.Y, mPos.X + dx, mPos.Y + dy, out touch_x, out touch_y, out touch_d))
            {
                MathVector.movePolar(ref touch_x, ref touch_y, angle, -Parent.MinStep);
                mPos.SetX(touch_x);
                mPos.SetY(touch_y);
                return true;
            }
            mPos.AddX(dx);
            mPos.AddY(dy);
            return false;
        }


        /// <summary>
        /// 线性移动,只和地图碰撞
        /// </summary>
        /// <param name="dx"></param>
        /// <param name="dy"></param>
        /// <returns>和地图碰撞</returns>
        public bool moveLinearMap2(float dx, float dy)
        {
            float touch_x, touch_y, touch_d;
            if (Parent.PathFinder.GetLineTouchPoint(mPos.X, mPos.Y, mPos.X + dx, mPos.Y + dy, out touch_x, out touch_y, out touch_d))
            {
                MathVector.movePolar(ref touch_x, ref touch_y, MathVector.getDegree(dx, dy), -Parent.MinStep);
                mPos.SetX(touch_x);
                mPos.SetY(touch_y);
                return true;
            }
            mPos.AddX(dx);
            mPos.AddY(dy);
            return false;
        }


        /// <summary>
        /// 线性移动,不会穿
        /// </summary>
        /// <param name="distance"></param>
        /// <param name="angle"></param>
        /// <param name="ignore_map"></param>
        /// <param name="ignore_obj"></param>
        /// <returns></returns>
        public MoveBlockResult moveLinear(float distance, float angle, bool ignore_map = false, bool ignore_obj = true)
        {
            MoveBlockResult ret = new MoveBlockResult();
            float dx = (float)(Math.Cos(angle) * distance);
            float dy = (float)(Math.Sin(angle) * distance);
            float dst_x = mPos.X + dx;
            float dst_y = mPos.Y + dy;
            float tgt_x = dst_x;
            float tgt_y = dst_y;
            if (!ignore_map)
            {
                float touch_x, touch_y, touch_d;
                if (Parent.PathFinder.GetLineTouchPoint(mPos.X, mPos.Y, dst_x, dst_y, out touch_x, out touch_y, out touch_d))
                {
                    ret.result |= MoveResult.MOVE_RESULT_TOUCH_MAP_ALL;
                    if (dst_x == touch_x && dst_y == touch_y)
                    {
                        ret.result |= MoveResult.MOVE_RESULT_BLOCK_MAP;
                        return ret;
                    }
                    float minstep = Parent.MinStep;
                    MathVector.movePolar(ref touch_x, ref touch_y, angle, -minstep);
                    dst_x = touch_x;
                    dst_y = touch_y;
                    distance = (touch_d - minstep);
                }
            }
            using (var list = ListObjectPool<InstanceZoneObject>.AllocAutoRelease())
            {
                if (!ignore_obj)
                {
                    Parent.getObjectsRoundLineRange<InstanceZoneObject>(
                       Collider.Object_BlockBody_TouchRoundLine,
                       mPos.X, mPos.Y, dst_x, dst_y, BodyBlockSize,
                       list, AoiStatus);
                }
                else if (!ignore_map)
                {
                    Parent.getObjectsRoundLineRange<InstanceZoneObject>((o, x1, y1, x2, y2, r) =>
                    {
                        if (o.IsStaticBlockable && o.IntersectObj)
                        {
                            return Collider.Object_BlockBody_TouchRoundLine(o, x1, y1, x2, y2, r);
                        }
                        return false;
                    }, mPos.X, mPos.Y, dst_x, dst_y, BodyBlockSize, list, AoiStatus);
                }
                if (list.Count > 0)
                {
                    list.Sort(new ObjectBodySorterNearest<InstanceZoneObject>(mPos.X, mPos.Y, this.BodyBlockSize));
                    ret.result |= MoveResult.MOVE_RESULT_BLOCK_OBJ;
                    ret.obj = list[0];

                    distance = MathVector.getDistance(mPos.X, mPos.Y, ret.obj.X, ret.obj.Y) - this.BodyBlockSize - ret.obj.BodyBlockSize;
                    distance = Math.Max(distance, 0);
                    dx = (float)(Math.Cos(angle) * distance);
                    dy = (float)(Math.Sin(angle) * distance);
                    dst_x = mPos.X;
                    dst_y = mPos.Y;
                    if (!ignore_map)
                    {
                        Parent.TryMoveToMapBorder(this, ref dst_x, ref dst_y, dx, dy);
                    }
                    else
                    {
                        dst_x += dx;
                        dst_y += dy;
                    }
                }
            }
            mPos.SetX(dst_x);
            mPos.SetY(dst_y);
            if (tgt_x == dst_x && tgt_y == dst_y)
            {
                ret.result |= MoveResult.MOVE_RESULT_ARRIVED;
            }
            return ret;
        }


        public bool moveBlink(BlinkMove blink, Vector2 targetPos = null, InstanceZoneObject targetUnit = null)
        {
            switch (blink.MType)
            {
                case BlinkMove.BlinkMoveType.MoveToForward:
                    moveLinear(blink.Distance,
                            mDirection + blink.DirectionOffset,
                            blink.NoneTouchMap || !IntersectMap,
                            blink.NoneTouchObj || !IntersectObj);
                    return true;
                case BlinkMove.BlinkMoveType.MoveToBackward:
                    moveLinear(-blink.Distance,
                            mDirection + blink.DirectionOffset,
                            blink.NoneTouchMap || !IntersectMap,
                            blink.NoneTouchObj || !IntersectObj);
                    return true;
                case BlinkMove.BlinkMoveType.MoveToTargetPos:
                    if (targetPos != null)
                    {
                        if (CMath.includeRoundPoint(X, Y, blink.Distance, targetUnit.X, targetUnit.Y))
                        {
                            float angle = MathVector.getDegree(this.X, this.Y, targetPos.X, targetPos.Y);
                            float distance = Math.Max(MathVector.getDistance(this.X, this.Y, targetPos.X, targetPos.Y), blink.Distance);
                            moveLinear(distance,
                                angle + blink.DirectionOffset,
                                blink.NoneTouchMap || !IntersectMap,
                                blink.NoneTouchObj || !IntersectObj);
                            return true;
                        }
                    }
                    break;
                case BlinkMove.BlinkMoveType.MoveToTargetUnitFace:
                    if (targetUnit != null)
                    {
                        if (CMath.includeRoundPoint(X, Y, blink.Distance, targetUnit.X, targetUnit.Y))
                        {
                            mPos.SetX(targetUnit.X);
                            mPos.SetY(targetUnit.Y);
                            mDirection = targetUnit.Direction + CMath.PI_F + blink.DirectionOffset;
                            moveLinear(
                                targetUnit.BodyBlockSize + this.BodyBlockSize,
                                targetUnit.Direction,
                                blink.NoneTouchMap || !IntersectMap,
                                blink.NoneTouchObj || !IntersectObj);
                            return true;
                        }
                    }
                    break;
                case BlinkMove.BlinkMoveType.MoveToTargetUnitBack:
                    if (targetUnit != null)
                    {
                        if (CMath.includeRoundPoint(X, Y, blink.Distance, targetUnit.X, targetUnit.Y))
                        {
                            mPos.SetX(targetUnit.X);
                            mPos.SetY(targetUnit.Y);
                            mDirection = targetUnit.Direction + blink.DirectionOffset;
                            moveLinear(
                                -(targetUnit.BodyBlockSize + this.BodyBlockSize),
                                targetUnit.Direction,
                                blink.NoneTouchMap || !IntersectMap,
                                blink.NoneTouchObj || !IntersectObj);
                            return true;
                        }
                    }
                    break;
            }
            return false;
        }

        /// <summary>
        /// 挤开其他和自己重叠的单位,或者被Weight大于自己的人挤开
        /// </summary>
        /// <returns></returns>
        public bool ElasticOtherObjects()
        {
            bool force_sync = false;
            Parent.ForEachNearObjects(X, Y, (InstanceZoneObject o, ref bool cancel) =>
            {
                if ((o != this) && (o.IntersectObj) && Parent.TouchObject2(this, o))
                {
                    if (ElasticOtherObject(o))
                    {
                        force_sync = true;
                    }
                }
            });
            return force_sync;
        }
        /// <summary>
        /// 挤开其他和自己重叠的单位,或者被Weight大于自己的人挤开
        /// </summary>
        /// <param name="o"></param>
        /// <returns>自己发生位移</returns>
        public bool ElasticOtherObject(InstanceZoneObject o)
        {
            float targetAngle = (float)(RandomN.NextDouble() * CMath.PI_MUL_2);
            float ddr = MathVector.getDistance(this.X, this.Y, o.X, o.Y);
            if (ddr > 0)
            {
                targetAngle = MathVector.getDegree(this.X, this.Y, o.X, o.Y);
            }
            float bdr = (this.BodyBlockSize + o.BodyBlockSize);
            float d = (bdr - ddr);
            if (!o.Moveable)
            {
                this.moveImpactDistance(targetAngle, -d);
                return true;
            }
            else if (o.Weight > this.Weight)
            {
                this.moveImpactDistance(targetAngle, -d);
                return true;
            }
            else
            {
                o.moveImpactDistance(targetAngle, d);
                return false;
            }
        }

    }

}