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;
}
}
}
}