using System; using System.Collections.Generic; using System.Text; using CommonAI.RTS; using CommonLang.Vector; using CommonLang; using CommonAI.Zone.Helper; using CommonAI.RTS.Manhattan; using CommonAI.Zone.ZoneEditor; namespace CommonAI.Zone.Instance { public abstract class InstanceFlag : GameEntity, IPositionObject { public abstract float Direction { get; } public abstract float RadiusSize { get; } public InstanceZone Parent { get { return mParent; } } public string Name { get { return mName; } } public string Alias { get { return mAlias; } } public Vector2 Pos { get { return mPos; } } public float X { get { return mPos.X; } } public float Y { get { return mPos.Y; } } private Vector2 mPos = new Vector2(); private readonly string mName; private readonly string mAlias; private readonly string mSrcTag = null; private bool mEnableTriggerd = false; private bool mEnable = true; private InstanceZone mParent; private string mTag; public bool Enable { get { return mEnable; } set { if (!mEnableTriggerd || mEnable != value) { mEnableTriggerd = true; mEnable = value; if (mEnable) { if (mOnFlagEnabled != null) mOnFlagEnabled.Invoke(this); } else { if (mOnFlagDisabled != null) mOnFlagDisabled.Invoke(this); } } } } public string Tag { get { return mTag; } set { if (mTag != value) { mTag = value; Parent.queueEvent(new FlagTagChangedEvent(this.mName, this.mTag)); } } } public string SrcTag { get { return mSrcTag; } } public InstanceFlag(InstanceZone zone, ZoneEditor.SceneObjectData data) { this.mParent = zone; this.mName = data.Name; this.mAlias = data.Alias; this.mPos = new Vector2(data.X, data.Y); this.mTag = data.Tag; } protected override void Disposing() { base.Disposing(); this.clearEvents(); } virtual internal void onAdded() { if (mOnInit != null) { mOnInit.Invoke(this); } } protected internal virtual void OnStart() { } virtual internal void update() { } abstract public TVector2 getRandomPos(Random random); //---------------------------------------------------------------------------- #region IFlagAPI public bool get_enable() { return Enable; } public bool set_enable(bool e) { Enable = e; return e; } public string get_name() { return Name; } public float get_x() { return X; } public float get_y() { return Y; } /// /// Show Check Point /// /// public void look_at_target(string target) { mParent.queueEvent(new LookAtEvent(target, 0, 0)); } #endregion //---------------------------------------------------------------------------- #region Delegate /// /// 触发器开始 /// /// public delegate void InitHandler(InstanceFlag flag); /// /// 触发器被开启 /// /// public delegate void FlagEnabledHandler(InstanceFlag flag); /// /// 触发器被关闭 /// /// public delegate void FlagDisabledHandler(InstanceFlag flag); private InitHandler mOnInit; private FlagEnabledHandler mOnFlagEnabled; private FlagDisabledHandler mOnFlagDisabled; public event InitHandler OnInit { add { mOnInit += value; } remove { mOnInit -= value; } } public event FlagEnabledHandler OnFlagEnabled { add { mOnFlagEnabled += value; } remove { mOnFlagEnabled -= value; } } public event FlagDisabledHandler OnFlagDisabled { add { mOnFlagDisabled += value; } remove { mOnFlagDisabled -= value; } } protected virtual void clearEvents() { mOnInit = null; mOnFlagEnabled = null; mOnFlagDisabled = null; } #endregion //---------------------------------------------------------------------------- } public class ZoneRegion : InstanceFlag, ViewTrigger.ViewTriggerListener { public ZoneEditor.RegionData.Shape RegionType { get { return mShape; } } /// /// Center of the position /// public override float RadiusSize { get { return R; } } public override float Direction { get { return 0; } } public float Width { get { return W; } } public float Height { get { return H; } } public float Radius { get { return R; } } readonly private ZoneEditor.RegionData.Shape mShape; private float W; private float H; private float R; private ViewTrigger mViewTrigger; private bool mAllTriggerOver = false; private bool mAllTriggerNoneAlive = false; private List mSpawnTriggers = new List(); public ZoneRegion(InstanceZone zone, ZoneEditor.RegionData data) : base(zone, data) { this.mShape = data.RegionType; this.W = data.W; this.H = data.H; this.R = data.Radius; switch (mShape) { case ZoneEditor.RegionData.Shape.RECTANGLE: this.mViewTrigger = new ViewTriggerRectCenter(Parent, W, H); break; case ZoneEditor.RegionData.Shape.STRIP: this.mViewTrigger = new ViewTriggerStripCenter(Parent, W, H, data.StripDirection); break; case ZoneEditor.RegionData.Shape.ROUND: default: this.mViewTrigger = new ViewTriggerRoundCenter(Parent, R); break; } this.mViewTrigger.setListener(this); } public override TVector2 getRandomPos(Random random) { if (mShape == ZoneEditor.RegionData.Shape.ROUND) { float angle = (float)(random.NextDouble() * CMath.PI_MUL_2); float len = (float)(random.NextDouble() * R); float x = X + (float)(Math.Cos(angle) * len); float y = Y + (float)(Math.Sin(angle) * len); return new TVector2(x, y); } else { float x = X + (float)((-W / 2f) + random.NextDouble() * W); float y = Y + (float)((-H / 2f) + random.NextDouble() * H); return new TVector2(x, y); } } public bool IsUnitInRegion(InstanceZoneObject unit) { return Collider.Object_BlockBody_TouchRound(unit, this.get_x(), this.get_y(), this.RadiusSize); ; } public void keepInRegion(ref float x, ref float y) { switch (mShape) { case ZoneEditor.RegionData.Shape.RECTANGLE: x = CMath.getInRange(x, this.X - this.W / 2, this.X + this.W / 2); y = CMath.getInRange(y, this.Y - this.H / 2, this.Y + this.H / 2); break; case ZoneEditor.RegionData.Shape.ROUND: float d = MathVector.getDistance(x, y, this.X, this.Y); if (d > this.R) { float a = MathVector.getDegree(x, y, this.X, this.Y); MathVector.movePolar(ref x, ref y, a, d - this.R); } break; } } protected override void Disposing() { base.Disposing(); mViewTrigger.Dispose(); foreach (var e in mSpawnTriggers) { e.OnLastObjectRemoved -= onTriggerLastObjectRemoved; e.Dispose(); } mSpawnTriggers.Clear(); mOnUnitEnter = null; mOnUnitLeave = null; mOnZoneUpdate = null; mOnSpawnOver = null; } internal void AddSpawnTrigger(AbstractSpawnTrigger trigger) { trigger.OnLastObjectRemoved += onTriggerLastObjectRemoved; mSpawnTriggers.Add(trigger); mAllTriggerOver = false; } private void onTriggerLastObjectRemoved(ZoneRegion region, AbstractSpawnTrigger trigger, InstanceZoneObject unit) { if (mOnSpawnOver != null && IsSpawnOver) { mOnSpawnOver.Invoke(this); } } /// /// 获取此区域绑定的怪物刷新点 /// /// public IEnumerable GetSpawnTriggers() { return mSpawnTriggers; } /// /// 获取此区域绑定的怪物刷新点 /// /// /// public AbstractSpawnTrigger GetSpawnTrigger(string name) { for (int i = mSpawnTriggers.Count - 1; i >= 0; --i) { AbstractSpawnTrigger tg = mSpawnTriggers[i]; if (string.Equals(tg.Name, name)) { return tg; } } return null; } /// /// 检测是否所有刷怪点都结束 /// public bool IsSpawnOver { get { if (!mAllTriggerOver) { for (int i = mSpawnTriggers.Count - 1; i >= 0; --i) { AbstractSpawnTrigger tg = mSpawnTriggers[i]; if (!tg.IsSpawnOver) { return false; } } mAllTriggerOver = true; } return true; } } /// /// 检测是否所有刷怪点都无存活 /// public bool IsSpawnNoneAlive { get { if (!mAllTriggerNoneAlive) { for (int i = mSpawnTriggers.Count - 1; i >= 0; --i) { AbstractSpawnTrigger tg = mSpawnTriggers[i]; if (!tg.IsSpawnOver) { return false; } if (tg.AliveCount > 0) { return false; } } mAllTriggerNoneAlive = true; } return true; } } internal override void update() { base.update(); if (Enable && (mOnUnitEnter != null || mOnUnitLeave != null || mEnterOnceList.Count > 0 || mLeaveOnceList.Count > 0)) { mViewTrigger.Enable = true; mViewTrigger.onLookUpdate(X, Y); } else { mViewTrigger.Enable = false; } if (Enable && mOnZoneUpdate != null) { mOnZoneUpdate.Invoke(this); } } void ViewTrigger.ViewTriggerListener.onObjectEnterView(ViewTrigger src, InstanceZoneObject obj) { if (mOnUnitEnter != null) { mOnUnitEnter.Invoke(this, obj as InstanceUnit); } mEnterOnceList.Invoke(this, obj as InstanceUnit); } void ViewTrigger.ViewTriggerListener.onObjectLeaveView(ViewTrigger src, InstanceZoneObject obj) { if (mOnUnitLeave != null) { mOnUnitLeave.Invoke(this, obj as InstanceUnit); } mLeaveOnceList.Invoke(this, obj as InstanceUnit); } bool ViewTrigger.ViewTriggerListener.select(ViewTrigger src, InstanceZoneObject obj) { return obj is InstanceUnit; } public void addInRegionViewed(InstanceUnit unit) { if (mViewTrigger != null) { mViewTrigger.addViewed(unit); } } /// /// 获得所有由此刷新点产生的单位 /// /// /// public void getSpawnedObjectsInRegion(List list) where T : InstanceZoneObject { foreach (var spawn in mSpawnTriggers) { spawn.getSpawnedObjects(list); } } //[Obsolete] //private List getObjectsInRegion(ObjectAoiStatus aoi) where T : InstanceZoneObject //{ // if (this.RegionType == ZoneEditor.RegionData.Shape.RECTANGLE) // { // return Parent.getObjectsRectRange( // Collider.Object_Pos_IncludeInRect, // this.X, this.Y, this.Width, this.Height , aoi); // } // else // { // return Parent.getObjectsRoundRange( // Collider.Object_Pos_IncludeInRound, // this.X, this.Y, this.Radius, aoi); // } //} public void getObjectsInRegion(List list, ObjectAoiStatus aoi = null) where T : InstanceZoneObject { if (this.RegionType == ZoneEditor.RegionData.Shape.RECTANGLE) { Parent.getObjectsRectRange( Collider.Object_Pos_IncludeInRect, this.X - this.Width/2, this.Y- this.Height/2, this.X + this.Width/2, this.Y + this.Height/2, list, aoi); } else { Parent.getObjectsRoundRange( Collider.Object_Pos_IncludeInRound, this.X, this.Y, this.Radius, list, aoi); } } public int getObjectsCountInRegion(ObjectAoiStatus aoi = null) where T : InstanceZoneObject { if (this.RegionType == ZoneEditor.RegionData.Shape.RECTANGLE) { return Parent.getObjectsCountRectRange(Collider.Object_Pos_IncludeInRect, this.X - this.Width / 2, this.Y - this.Height / 2, this.X + this.Width / 2, this.Y + this.Height / 2, aoi); } else { return Parent.getObjectsCountRoundRange( Collider.Object_Pos_IncludeInRound, this.X, this.Y, this.Radius, aoi); } } //[Obsolete] //private List getObjectsInRegion(Select select, ObjectAoiStatus aoi) where T : InstanceZoneObject //{ // List list = getObjectsInRegion(); // for (int i = list.Count - 1; i >= 0; --i) // { // if (!select.Invoke(list[i])) // { // list.RemoveAt(i); // } // } // return list; //} public int getObjectsCountInRegion(Select select , ObjectAoiStatus aoi = null) where T : InstanceZoneObject { int ret = 0; using (var list = ListObjectPool.AllocAutoRelease()) { getObjectsInRegion(list , aoi); for (int i = list.Count - 1; i >= 0; --i) { if (select.Invoke(list[i])) { ret++; } } } return ret; } //-------------------------------------------------------------------------------------------------------------- #region Delegate /// /// 某单位进入此区域 /// /// /// public delegate void UnitEnterHandler(ZoneRegion region, InstanceUnit obj); /// /// 某单位离开此区域 /// /// /// public delegate void UnitLeaveHandler(ZoneRegion region, InstanceUnit obj); /// /// 区域更新 /// /// public delegate void ZoneUpdateHandler(ZoneRegion region); /// /// 刷新点刷新完毕 /// /// public delegate void SpawnOverHandler(ZoneRegion region); private UnitEnterHandler mOnUnitEnter; private UnitLeaveHandler mOnUnitLeave; private ZoneUpdateHandler mOnZoneUpdate; private SpawnOverHandler mOnSpawnOver; public event UnitEnterHandler OnUnitEnter { add { mOnUnitEnter += value; } remove { mOnUnitEnter -= value; } } public event UnitLeaveHandler OnUnitLeave { add { mOnUnitLeave += value; } remove { mOnUnitLeave -= value; } } public event ZoneUpdateHandler OnZoneUpdate { add { mOnZoneUpdate += value; } remove { mOnZoneUpdate -= value; } } public event SpawnOverHandler OnSpawnOver { add { mOnSpawnOver += value; } remove { mOnSpawnOver -= value; } } //-------------------------------------------------------------------------------------------------------------- private struct OnceEvent : IOnceInvoke { public InstanceUnit unit { get; private set; } public bool IsDone { get { return done || !unit.Enable; } } private UnitEnterHandler enter_handler; private UnitLeaveHandler leave_handler; private bool done; public OnceEvent(InstanceUnit unit, UnitEnterHandler enter, UnitLeaveHandler leave) { this.unit = unit; this.enter_handler = enter; this.leave_handler = leave; this.done = false; } public void Invoke(ZoneRegion region) { if (enter_handler != null) this.enter_handler.Invoke(region, unit); if (leave_handler != null) this.leave_handler.Invoke(region, unit); this.enter_handler = null; this.leave_handler = null; this.done = true; } } private class OnceInvokeList : OnceInvokeList { public void Invoke(ZoneRegion region, InstanceUnit unit) { base.Invoke((e) => { if (e.unit == unit) { e.Invoke(region); } }); } } private OnceInvokeList mEnterOnceList = new OnceInvokeList(); private OnceInvokeList mLeaveOnceList = new OnceInvokeList(); /// /// 监听单位进入一次,触发器只触发一次 /// /// /// public void ListenUnitEnterOnce(InstanceUnit unit, UnitEnterHandler handler) { mEnterOnceList.Add(new OnceEvent(unit, handler, null)); } /// /// 监听单位离开一次,触发器只触发一次 /// /// /// public void ListenUnitLeaveOnce(InstanceUnit unit, UnitLeaveHandler handler) { mLeaveOnceList.Add(new OnceEvent(unit, null, handler)); } //-------------------------------------------------------------------------------------------------------------- protected override void clearEvents() { base.clearEvents(); mEnterOnceList.Clear(); mLeaveOnceList.Clear(); mOnUnitEnter = null; mOnUnitLeave = null; mOnZoneUpdate = null; mOnSpawnOver = null; } #endregion } public class ZoneWayPoint : InstanceFlag { public override float RadiusSize { get { return 1; } } public override float Direction { get { return 0; } } private IList mNexts = new List(); public ZoneWayPoint(InstanceZone zone, ZoneEditor.PointData data) : base(zone, data) { } public override TVector2 getRandomPos(Random random) { return new TVector2(X, Y); } internal override void update() { base.update(); } internal void AddNext(ZoneWayPoint next) { mNexts.Add(next); } public ZoneWayPoint GetRandomNext(ZoneWayPoint prev = null) { if (mNexts.Count > 0) { if (mNexts.Count == 1) { return mNexts[0]; } int nexti = Parent.RandomN.Next(0, mNexts.Count); for (int i = 0; i < mNexts.Count; i++) { int idx = CMath.cycNum(nexti, i, mNexts.Count); if (mNexts[idx] != prev) { return mNexts[idx]; } } return mNexts[nexti]; } return null; } public ZoneWayPoint GetNext() { if (mNexts.Count > 0) { return mNexts[0]; } return null; } public ZoneWayPoint GetTail() { if (mNexts.Count == 0) { return this; } ZoneWayPoint wp = GetNext(); while (true) { ZoneWayPoint next = wp.GetNext(); if (next != null) { wp = next; } else { break; } } return wp; } } public class ZoneDecoration : InstanceFlag { public override float RadiusSize { get { return this.R; } } public override float Direction { get { return this.StripDirection; } } readonly private ZoneEditor.DecorationData.Shape mShape; private float W; private float H; private float R; private float StripDirection; private bool Blockable; private int BlockValue; public ZoneDecoration(InstanceZone zone, ZoneEditor.DecorationData data) : base(zone, data) { this.mShape = data.RegionType; this.W = data.W; this.H = data.H; this.R = data.Radius; this.StripDirection = data.StripDirection; this.Blockable = data.Blockable; this.BlockValue = data.BlockValue; this.OnFlagEnabled += this.OnEnabled; this.OnFlagDisabled += this.OnDisabled; if (Blockable) { this.OnFlagEnabled += this.OnTerrainEnabled; this.OnFlagDisabled += this.OnTerrainDisabled; } } internal override void update() { base.update(); } public override TVector2 getRandomPos(Random random) { if (mShape == ZoneEditor.DecorationData.Shape.ROUND) { float angle = (float)(random.NextDouble() * CMath.PI_MUL_2); float len = (float)(random.NextDouble() * R); float x = X + (float)(Math.Cos(angle) * len); float y = Y + (float)(Math.Sin(angle) * len); return new TVector2(x, y); } else { float x = X + (float)((-W / 2f) + random.NextDouble() * W); float y = Y + (float)((-H / 2f) + random.NextDouble() * H); return new TVector2(x, y); } } private void OnEnabled(InstanceFlag flag) { Parent.queueEvent(new DecorationChangedEvent(Name, true)); } private void OnDisabled(InstanceFlag flag) { Parent.queueEvent(new DecorationChangedEvent(Name, false)); } #region FillTerrain private void OnTerrainEnabled(InstanceFlag flag) { this.FillTerrain(fill_Terrain_value); } private void OnTerrainDisabled(InstanceFlag flag) { this.FillTerrain(fill_Terrain_reset); } private void fill_Terrain_value(int bx, int by) { Parent.PathFinder.TryFillTerrain(bx, by, BlockValue); } private void fill_Terrain_reset(int bx, int by) { Parent.PathFinder.TryFillTerrain(bx, by, Parent.TerrainSrc.TerrainMatrix[bx, by]); } protected void FillTerrain(AstarManhattan.ForEachTerrainAction fillAction) { var mmap = Parent.PathFinder.MMap; switch (this.mShape) { case ZoneEditor.DecorationData.Shape.RECTANGLE: AstarManhattan.ForEachTerrainRect(mmap, X - W / 2, Y - H / 2, W, H, fillAction); break; case ZoneEditor.DecorationData.Shape.ROUND: AstarManhattan.ForEachTerrainEllipse(mmap, X - W / 2, Y - H / 2, W, H, fillAction); break; case ZoneEditor.DecorationData.Shape.STRIP: TLine2 line = new TLine2(X, Y, X, Y); MathVector.movePolarExt(ref line.p, StripDirection, -H / 2); MathVector.movePolarExt(ref line.q, StripDirection, +H / 2); AstarManhattan.ForEachTerrainStripWidth(mmap, line.p.X, line.p.Y, line.q.X, line.q.Y, W / 2, fillAction); break; } Parent.PathFinder.BeginFindPath(); } public bool TouchBlock(float x, float y) { if (Blockable && Enable && Parent.PathFinder.MMap.TestBlockValue(this.BlockValue)) { int bx = (((int)x) / Parent.TerrainSrc.GridCellW); int by = (((int)y) / Parent.TerrainSrc.GridCellH); var mmap = Parent.PathFinder.MMap; switch (this.mShape) { case ZoneEditor.DecorationData.Shape.RECTANGLE: return AstarManhattan.ForEachTerrainRect(mmap, X - W / 2, Y - H / 2, W, H, (cx, cy) => { return cx == bx && cy == by; }); case ZoneEditor.DecorationData.Shape.ROUND: return AstarManhattan.ForEachTerrainEllipse(mmap, X - W / 2, Y - H / 2, W, H, (cx, cy) => { return cx == bx && cy == by; }); case ZoneEditor.DecorationData.Shape.STRIP: TLine2 line = new TLine2(X, Y, X, Y); MathVector.movePolarExt(ref line.p, StripDirection, -H / 2); MathVector.movePolarExt(ref line.q, StripDirection, +H / 2); return AstarManhattan.ForEachTerrainStripWidth(mmap, line.p.X, line.p.Y, line.q.X, line.q.Y, W / 2, (cx, cy) => { return cx == bx && cy == by; }); } } return false; } #endregion } public class ZoneArea : InstanceFlag { public override float RadiusSize { get { return this.R; } } public override float Direction { get { return 0; } } public int CurrentMapNodeValue { get; private set; } private float W; private float H; private float R; public ZoneArea(InstanceZone zone, ZoneEditor.AreaData data) : base(zone, data) { this.W = data.W; this.H = data.H; this.R = data.W / 2; } internal void BindMapBlock(AreaData data) { //var current_node = Parent.PathFinder.GetMapNodeByPos(X, Y); //if (current_node != null) { this.CurrentMapNodeValue = data.Color; var list = Parent.TerrainAreaGenerator.GetContinuousMapNode(X, Y, W / 2, H / 2); foreach (var index in list) { var node = Parent.PathFinder.GetMapNode(index.BX, index.BY) as ZoneMapNode; if (node != null) { node.SetServerArea(this); } } } } public override TVector2 getRandomPos(Random random) { return new TVector2(X, Y); } internal void do_onUnitEnter(InstanceZoneObject obj) { if (obj is InstanceUnit) { if (mOnUnitEnter != null) mOnUnitEnter.Invoke(this, obj as InstanceUnit); if (mEnterOnceList.Count > 0) mEnterOnceList.Invoke(this, obj as InstanceUnit); } } internal void do_onUnitLeave(InstanceZoneObject obj) { if (obj is InstanceUnit) { if (mOnUnitLeave != null) mOnUnitLeave.Invoke(this, obj as InstanceUnit); if (mLeaveOnceList.Count > 0) mLeaveOnceList.Invoke(this, obj as InstanceUnit); } } //---------------------------------------------------------------------------- #region Delegate /// /// 某单位进入此区域 /// /// /// public delegate void UnitEnterHandler(ZoneArea area, InstanceUnit obj); /// /// 某单位离开此区域 /// /// /// public delegate void UnitLeaveHandler(ZoneArea area, InstanceUnit obj); private UnitEnterHandler mOnUnitEnter; private UnitLeaveHandler mOnUnitLeave; public event UnitEnterHandler OnUnitEnter { add { mOnUnitEnter += value; } remove { mOnUnitEnter -= value; } } public event UnitLeaveHandler OnUnitLeave { add { mOnUnitLeave += value; } remove { mOnUnitLeave -= value; } } //---------------------------------------------------------------------------- private struct OnceEvent : IOnceInvoke { public InstanceUnit unit { get; private set; } public bool IsDone { get { return done || !unit.Enable; } } private UnitEnterHandler enter_handler; private UnitLeaveHandler leave_handler; private bool done; public OnceEvent(InstanceUnit unit, UnitEnterHandler enter, UnitLeaveHandler leave) { this.unit = unit; this.enter_handler = enter; this.leave_handler = leave; this.done = false; } public void Invoke(ZoneArea area) { if (enter_handler != null) this.enter_handler.Invoke(area, unit); if (leave_handler != null) this.leave_handler.Invoke(area, unit); this.enter_handler = null; this.leave_handler = null; this.done = true; } } private class OnceInvokeList : OnceInvokeList { public void Invoke(ZoneArea area, InstanceUnit unit) { base.Invoke((e) => { if (e.unit == unit) { e.Invoke(area); } }); } } private OnceInvokeList mEnterOnceList = new OnceInvokeList(); private OnceInvokeList mLeaveOnceList = new OnceInvokeList(); /// /// 监听单位进入一次,触发器只触发一次 /// /// /// public void ListenUnitEnterOnce(InstanceUnit unit, UnitEnterHandler handler) { mEnterOnceList.Add(new OnceEvent(unit, handler, null)); } /// /// 监听单位离开一次,触发器只触发一次 /// /// /// public void ListenUnitLeaveOnce(InstanceUnit unit, UnitLeaveHandler handler) { mLeaveOnceList.Add(new OnceEvent(unit, null, handler)); } //---------------------------------------------------------------------------- protected override void clearEvents() { base.clearEvents(); mEnterOnceList.Clear(); mLeaveOnceList.Clear(); mOnUnitEnter = null; mOnUnitLeave = null; } #endregion //---------------------------------------------------------------------------- } }