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); /// /// 活动实例数量 /// public static int ActiveObjectCount { get { return s_active_object_count.Value; } } /// /// 分配实例数量 /// public static int AllocObjectCount { get { return s_alloc_object_count.Value; } } //------------------------------------------------------------------------------------------------ public TemplateManager Templates { get { return mZone.Templates; } } /// /// 获得当前空间分割节点 /// public SpaceDivision.SpaceCellNode CurrentSpaceCellNode { get { return mCurCellNode.cell; } } /// /// 是否为静态阻挡物 /// readonly public bool IsStaticBlockable; private Vector2 mPos = new Vector2(); 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 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; } } /// /// 是否已被添加到场景 /// public bool IsInZone { get { return mAdded; } } /// /// 是否未被从场景移除 /// 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; } /// /// BodyBlockSize /// public float RadiusSize { get { return BodyBlockSize; } } /// /// 朝向 /// virtual public float Direction { get { return mDirection; } set { mDirection = value; } } public Random RandomN { get { return mParentRandom; } } /// /// 总共存活了多久 /// public int PassTimeMS { get { return mQueryPassTimeMS; } } /// /// 从编辑器继承过来的参数 /// public string UnitTag { get { return mUnitTag; } set { this.mUnitTag = value; } } /// /// 是否被标记为暂停逻辑 /// public virtual bool IsPaused { get { return mIsPause; } } /// /// IAO标记 /// 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, uint customid = 0) { if (mAdded == false) { this.mAdded = true; this.mMarkRemoved = false; this.mID = customid > 0 ? customid : 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; } //---------------------------------------------------------------------------------------- /// /// 暂停逻辑 /// /// /// public virtual void Pause(bool pause, int timeMS = 0) { this.mIsPause = pause; if (pause && timeMS > 0) { this.mPauseTime = new TimeExpire(timeMS); } else { this.mPauseTime = null; } } //---------------------------------------------------------------------------------------- #region DELEGATE /// /// 单位添加到场景 /// /// public delegate void ObjectAddedHandler(InstanceZoneObject obj); /// /// 单位被移除触发 /// /// public delegate void ObjectRemovedHandler(InstanceZoneObject obj); /// /// 单位空间分割区域改变时触发 /// /// /// /// public delegate void ObjectSpaceChangedHandler(InstanceZoneObject obj, SpaceDivision.SpaceCellNode old_node, SpaceDivision.SpaceCellNode new_node); /// /// 单位空间分割区域改变时触发 /// /// /// /// public delegate void ObjectAreaChangedHandler(InstanceZoneObject obj, ZoneArea old_node, ZoneArea new_node); /// /// 单位发送事件时触发 /// /// /// 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 /// /// 地图阻挡 ? /// abstract public bool IntersectMap { get; } /// /// 单位阻挡 /// abstract public bool IntersectObj { get; } /// /// 是否可以动 /// abstract public bool Moveable { get; } /// /// 自身体积(半径) /// abstract public float BodyBlockSize { get; } /// /// 受击半径 /// abstract public float BodyHitSize { get; } /// /// 身体高度 /// abstract public float BodyHeight { get; } /// /// 是否同步客户端 /// abstract public bool ClientVisible { get; } abstract public float Weight { get; } /// /// 是否允许帧同步 /// abstract public bool SyncPos { get; } abstract protected void onUpdate(bool slowRefresh); abstract protected void onAdded(bool pointLv); abstract protected void onRemoved(); /* /// /// 被攻击到 /// /// /// /// virtual internal bool onHitAttack(InstanceUnit sender, AttackProp attack) { return false; } */ /// /// 获取同步信息 /// abstract public SyncObjectInfo GenSyncInfo(bool network); #endregion //--------------------------------------------------------------------------------------- /// /// 直接转向 /// /// /// 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))); } /// /// 直接转向 /// /// public virtual void faceTo(float d) { this.mDirection = d; } /// /// 基于当前角度转向 /// /// 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) { } /// /// 在移动时被某个单位阻挡 /// /// protected virtual void onMoveBlockWithObject(InstanceZoneObject obj) { } /// /// 阻挡到其他单位移动 /// /// /// 通知其他单位自己可以让开 protected virtual bool onBlockOther(InstanceZoneObject obj) { return false; } //--------------------------------------------------------------------------------------------------------- /// /// 无碰撞移动 /// /// /// /// public void flyTo(float direction, float speedSEC, int intervalMS) { float distance = MoveHelper.GetDistance(intervalMS, speedSEC); MathVector.movePolar(mPos, direction, distance); } /// /// /// /// /// /// /// /// 是否到达终点 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; } /// /// 越过单位跳跃 /// /// /// /// /// /// 是否到达终点 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; } //--------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------- /// /// 移动到目标点 /// /// /// /// /// 可以顺利移动 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); } /// /// 移动到目标点 /// /// /// /// /// /// 可以顺利移动 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 > 0 || ddy > 0) { if (ddx < minstep && ddy < minstep) { result.result |= MoveResult.MOVE_RESULT_MIN_STEP; } } return result; } } /// /// 尝试碰撞移动偏移量 /// /// /// /// 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; } /// /// 挤开对方的移动方式 /// /// /// /// /// /// TRUE=无法移动 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); } /// /// 挤开对方的移动方式 /// /// /// /// /// TRUE=无法移动 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; } } //-------------------------------------------------------------------------------------------------------// /// /// 线性移动,只和地图碰撞 /// /// /// /// 和地图碰撞 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; } /// /// 线性移动,只和地图碰撞 /// /// /// /// 和地图碰撞 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; } /// /// 线性移动,不会穿 /// /// /// /// /// /// 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.AllocAutoRelease()) { if (!ignore_obj) { Parent.getObjectsRoundLineRange( Collider.Object_BlockBody_TouchRoundLine, mPos.X, mPos.Y, dst_x, dst_y, BodyBlockSize, list, AoiStatus); } else if (!ignore_map) { Parent.getObjectsRoundLineRange((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(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; } /// /// 挤开其他和自己重叠的单位,或者被Weight大于自己的人挤开 /// /// 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; } /// /// 挤开其他和自己重叠的单位,或者被Weight大于自己的人挤开 /// /// /// 自己发生位移 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; } } } }