using System; using System.Collections.Generic; using System.Text; using CommonLang; using CommonAI.RTS; using CommonLang.Vector; using CommonAI.RTS.Manhattan; using CommonAI.Zone.Helper; using CommonAI.Data; namespace CommonAI.Zone.Instance { /// /// 生成单位的触发器 /// public abstract class AbstractSpawnTrigger : Ability { public string Name { get; private set; } private ZoneRegion mAdded = null; private int mSpawnTimeIntervalMS; private int mDelayTimeMS = 0; private int mSpawnOnceCount; private LaunchEffect mSpawnEffect; private bool mSpawnWithoutAlive = true; private bool mResetOnWithoutAlive = false; private int mTotalSpawnCount = 0; private int mSpawnIndexer = 0; private int mLimitedSpawnCount = 0; private int mLimitedAliveCount = 0; private HashMap mSpawnedUnits = new HashMap(); private string mUnitTag; private TimeTaskMS mTimeTask; private float mStartDirection = float.NaN; private TeamFormation mTeam; private TeamFormationGroup mTeamHelper; //绑定事件 //protected List Events = new List(); //-------------------------------------------------------------------------------------------------- public AbstractSpawnTrigger(InstanceZone zone, string name) : base(zone) { this.Name = name; } public InstanceZone BindingZone { get { return mAdded.Parent; } } public ZoneRegion BindingRegion { get { return mAdded; } } public int OnceSpawnCount { get { return mSpawnOnceCount; } } public int LimitedSpawnCount { get { return mLimitedSpawnCount; } } public int LimitedAliveCount { get { return mLimitedAliveCount; } } /// /// 当前存活数量 /// public virtual int AliveCount { get { return mSpawnedUnits.Count; } } public int SpawnIndexer { get { return mSpawnIndexer; } } public int TotalSpawnCount { get { return mTotalSpawnCount; } } public float StartDirection { get { return (!float.IsNaN(mStartDirection)) ? mStartDirection : (float)(Zone.RandomN.NextDouble() * CMath.PI_MUL_2); } } /// /// 是否已完成刷新 /// public bool IsSpawnOver { get { if (mLimitedSpawnCount == 0) return false; return (mTotalSpawnCount >= mLimitedSpawnCount); } } public bool IsWaitAlive { get { if (mLimitedAliveCount == 0) return false; return (mSpawnedUnits.Count >= mLimitedAliveCount); } } /// /// 生产单位间隔时间 /// /// public void setSpawnInterval(int interval) { this.mSpawnTimeIntervalMS = interval; } /// /// 设置每次产生个数 /// /// public void setSpawnCount(int count) { this.mSpawnOnceCount = count; } /// /// 设置出生特效 /// /// public void setSpawnEffect(LaunchEffect effect) { this.mSpawnEffect = effect; } /// /// 单位产生绑定的标志 /// /// public void setUnitTag(string tag) { this.mUnitTag = tag; } /// /// 只有当前怪物没有存活时才刷新 /// /// public void setSpawnWithoutAlive(bool without_alive) { this.mSpawnWithoutAlive = without_alive; } /// /// 设置怪物存活最大上限 /// /// public void setLimitedAliveCount(int count) { this.mLimitedAliveCount = count; } /// /// 设置怪物最大产生数量 /// /// public void setLimitedSpawnCount(int count) { this.mLimitedSpawnCount = count; } /// /// 设置当前触发器禁止时间,就是多长时间后才起效。 /// /// public void setDelayTime(int time) { this.mDelayTimeMS = time; } public void setStartDirection(float direction) { if (direction >= 0) { this.mStartDirection = direction; } } public void setTeamFormation(TeamFormation team) { this.mTeam = team; } public void setResetOnWithoutAlive(bool flag) { this.mResetOnWithoutAlive = flag; } public void getSpawnedObjects(List list) where T : InstanceZoneObject { foreach (var o in mSpawnedUnits.Values) { if (o is T) { list.Add(o as T); } } } /// /// 重置计时器 /// public void reset() { mTotalSpawnCount = 0; mSpawnedUnits.Clear(); if (mTimeTask != null) { mTimeTask.Reset(); } } /// /// 绑定到区域 /// /// public void bindToRegion(ZoneRegion region) { if (mAdded == null) { InstanceZone zone = region.Parent; mAdded = region; mTimeTask = zone.AddTimeTask(mSpawnTimeIntervalMS, mDelayTimeMS, 0, onTimeSpawn); region.OnFlagDisabled += this.onRegionStop; region.OnFlagEnabled += this.onRegionStart; region.AddSpawnTrigger(this); if (!region.Enable) { mTimeTask.Pause(); } else { //一开始就执行一次spawn spawnOnce(mAdded); } } else { throw new Exception("This Trigger already bind a region !!!"); } } private void onRegionStart(InstanceFlag region) { //一开始就执行一次spawn spawnOnce(mAdded); mTimeTask.Resume(); } private void onRegionStop(InstanceFlag region) { mTimeTask.Pause(); } private void onTimeSpawn(TimeTaskMS task) { spawnOnce(mAdded); } private void spawnOnce(ZoneRegion region) { if (SpawnTemplateCount <= 0) { return; } if (mSpawnWithoutAlive && mSpawnedUnits.Count > 0) { return; } InstanceZone zone = region.Parent; if (mTeam != null) { if (mTeamHelper == null || mTeamHelper.Data != mTeam) { mTeamHelper = new TeamFormationGroup(mTeam, region); } for (int i = mSpawnOnceCount - 1; i >= 0; --i) { var pos = region.getRandomPos(zone.RandomN); mTeamHelper.AddPos(pos.X, pos.Y, StartDirection); } mTeamHelper.ResetPos(); } else { mTeamHelper = null; } for (int i = mSpawnOnceCount - 1; i >= 0; --i) { if (IsSpawnOver) { break; } if (IsWaitAlive) { break; } var pos = (mTeamHelper != null) ? mTeamHelper.PopPos() : null; var obj = SpawnObject(pos); this.mSpawnIndexer++; this.mTotalSpawnCount++; if (obj != null) { this.mSpawnedUnits.Put(obj, obj); obj.UnitTag = mUnitTag; obj.OnObjectRemoved += removeSpawned; OnObjectSpawned(obj); if (mOnSpawnObject != null) { mOnSpawnObject.Invoke(region, this, obj); } if (mSpawnEffect != null) { zone.queueEvent(new AddEffectEvent(0 ,region.X, region.Y, region.Direction, mSpawnEffect)); } if (IsSpawnOver) { if (mOnSpawnOver != null) { mOnSpawnOver.Invoke(region, this); } } } } if (mTeamHelper != null) { mTeamHelper.Clear(); } if (mResetOnWithoutAlive) { this.mTimeTask.Pause(); } } private void removeSpawned(InstanceZoneObject obj) { obj.OnObjectRemoved -= removeSpawned; obj = mSpawnedUnits.RemoveByKey(obj); if (obj != null) { OnSpawnedObjectRemoved(obj); if (IsSpawnOver && mSpawnedUnits.Count == 0) { mTimeTask.Pause(); if (mOnLastObjectRemoved != null) { mOnLastObjectRemoved.Invoke(mAdded, this, obj); } } } if (IsSpawnOver == false && mSpawnedUnits.Count == 0 && mResetOnWithoutAlive) { this.mTimeTask.Reset(); } } //-------------------------------------------------------------------------------------------------- #region Delegate public override void Dispose() { base.Dispose(); mOnSpawnOver = null; mOnSpawnObject = null; mOnLastObjectRemoved = null; } public delegate void SpawnObjectHandler(ZoneRegion region, AbstractSpawnTrigger trigger, InstanceZoneObject unit); public delegate void SpawnOverHandler(ZoneRegion region, AbstractSpawnTrigger trigger); public delegate void SpawnLastObjectRemovedHandler(ZoneRegion region, AbstractSpawnTrigger trigger, InstanceZoneObject unit); private SpawnOverHandler mOnSpawnOver; private SpawnObjectHandler mOnSpawnObject; private SpawnLastObjectRemovedHandler mOnLastObjectRemoved; public event SpawnOverHandler OnSpawnOver { add { mOnSpawnOver += value; } remove { mOnSpawnOver -= value; } } public event SpawnObjectHandler OnSpawnUnit { add { mOnSpawnObject += value; } remove { mOnSpawnObject -= value; } } public event SpawnLastObjectRemovedHandler OnLastObjectRemoved { add { mOnLastObjectRemoved += value; } remove { mOnLastObjectRemoved -= value; } } #endregion //-------------------------------------------------------------------------------------------------- #region ABSTRACT abstract public int SpawnTemplateCount { get; } /// /// 创建并生成一个单位 /// /// abstract protected InstanceZoneObject SpawnObject(IPositionObject pos); /// /// 当一个单位被生成 /// /// abstract protected void OnObjectSpawned(InstanceZoneObject obj); /// /// 当被生成的单位被移除场景 /// /// abstract protected void OnSpawnedObjectRemoved(InstanceZoneObject obj); #endregion } //------------------------------------------------------------------------------------------- /// /// 生成单位的触发器 /// public class SpawnUnitTrigger : AbstractSpawnTrigger { public struct SpawnUnitInfo { public UnitInfo Unit; public int Level; public float Percent; public SpawnUnitInfo(UnitInfo unit, int level, float percent) { this.Unit = unit; this.Level = level; this.Percent = percent; } } private List mSpawnUnitTemplates = new List(); private HashMap mAlivedUnits = new HashMap(); private ZoneWayPoint mStartPath = null; private int mStartPathMinHoldTimeMS, mStartPathMaxHoldTimeMS; private int mPeaceTime; private byte mUnitForceMin; private byte mUnitForceMax; private string mUnitName; public override int SpawnTemplateCount { get { return mSpawnUnitTemplates.Count; } } public override int AliveCount { get { if (mAlivedUnits.Count > 0) { int count = 0; foreach(var u in mAlivedUnits.Values) { if (!u.IsDead()) { count++; } } return count; } return 0; } } public SpawnUnitTrigger(InstanceZone zone, string name) : base(zone, name) { } /// /// 设置产生单位的Force /// /// public void setUnitForce(byte forceMin, byte forceMax) { this.mUnitForceMin = forceMin; this.mUnitForceMax = forceMax; } /// /// 设置出生单位名字 /// /// public void setUnitName(string name) { this.mUnitName = name; } /// /// 添加单位模板 /// /// 将要产生的单位模板 /// /// public void addUnitInfo(UnitInfo info, int level, float percent) { this.mSpawnUnitTemplates.Add(new SpawnUnitInfo(info, level, percent)); } /// /// 添加单位模板 /// /// 将要产生的单位模板 /// /// public void addUnitInfo(int templateID, int level = 0, float percent = 100f) { UnitInfo info = Zone.Templates.getUnit(templateID); if (info != null) { info = (UnitInfo)info.Clone(); this.addUnitInfo(info, level, percent); } } //添加单位事件 //public void addItemEvent(string eventId) //{ // this.Events.Add(eventId); //} /// /// 添加多个单位模板 /// /// /// public void addUnits(int[] unitsTemplateID, int level) { if (unitsTemplateID != null) { foreach (int id in unitsTemplateID) { UnitInfo info = Zone.Templates.getUnit(id); if (info != null) { info = (UnitInfo)info.Clone(); this.addUnitInfo(info, level, 100f); } } } } /// /// 清除所有怪物模板 /// public void clearTemplates() { mSpawnUnitTemplates.Clear(); } /// /// 设置移动路线 /// /// /// /// /// public ZoneWayPoint setStartPath(InstanceZone zone, string flagName, int minHoldTimeMS, int maxHoldTimeMS, int PeaceTime) { this.mStartPath = null; if (!string.IsNullOrEmpty(flagName)) { InstanceFlag flag = zone.getFlag(flagName); if (flag is ZoneWayPoint) { mStartPath = flag as ZoneWayPoint; mStartPathMinHoldTimeMS = minHoldTimeMS; mStartPathMaxHoldTimeMS = maxHoldTimeMS; mPeaceTime = PeaceTime; } } return mStartPath; } protected override InstanceZoneObject SpawnObject(IPositionObject pos) { InstanceZone zone = this.BindingZone; SpawnUnitInfo spawn = mSpawnUnitTemplates[SpawnIndexer % mSpawnUnitTemplates.Count]; if (CUtils.RandomPercent(zone.RandomN, spawn.Percent)) { IVector2 mpos = pos != null ? new TVector2(pos.X, pos.Y) : BindingRegion.getRandomPos(zone.RandomN); float direction = pos != null ? pos.Direction : this.StartDirection; UnitInfo info = spawn.Unit; int level = spawn.Level; InstanceUnit unit = zone.AddUnit(info, mUnitName, this.GetForce(), level, mpos.X, mpos.Y, direction); if (unit is IGuardUnit) { IGuardUnit guard = unit as IGuardUnit; guard.SetOrginPosition(mpos.X, mpos.Y); } return unit; } return null; } private byte GetForce() { if (this.mUnitForceMax > this.mUnitForceMin && this.mUnitForceMin >= 0) { return (byte)(GlobalData.gRandom.Next() % (this.mUnitForceMax - this.mUnitForceMin) + this.mUnitForceMin); } return this.mUnitForceMin; } protected override void OnObjectSpawned(InstanceZoneObject obj) { InstanceUnit unit = (obj as InstanceUnit); if (unit != null) { mAlivedUnits.Put(unit.ID, unit); unit.OnDead += unit_OnDead; if (mStartPath != null && (unit is IGuardUnit)) { unit.OnActivated += unit_OnActivated; } } } protected override void OnSpawnedObjectRemoved(InstanceZoneObject obj) { IGuardUnit guard = (obj as IGuardUnit); if (guard != null) { var unit = guard as InstanceUnit; mAlivedUnits.RemoveByKey(unit.ID); unit.OnDead -= unit_OnDead; unit.OnActivated -= unit_OnActivated; } } private void unit_OnDead(InstanceUnit unit, InstanceUnit attacker) { mAlivedUnits.RemoveByKey(unit.ID); } private void unit_OnActivated(InstanceUnit unit) { unit.OnActivated -= unit_OnActivated; if (unit is IGuardUnit) { IGuardUnit guard = unit as IGuardUnit; if (mStartPathMinHoldTimeMS != 0 || mStartPathMaxHoldTimeMS != 0) { guard.PatrolWith( mStartPath, mStartPathMinHoldTimeMS, mStartPathMaxHoldTimeMS, mPeaceTime); } else { guard.AttackTo(mStartPath, mPeaceTime); } } } } //------------------------------------------------------------------------------------------- /// /// 生成物品的触发器 /// public class SpawnItemTrigger : AbstractSpawnTrigger { public struct SpawnItemInfo { public ItemTemplate Item; public float Percent; public SpawnItemInfo(ItemTemplate item, float percent) { this.Item = item; this.Percent = percent; } } private List mSpawnUnitTemplates = new List(); private byte mUnitForce; private string mUnitName; public override int SpawnTemplateCount { get { return mSpawnUnitTemplates.Count; } } public SpawnItemTrigger(InstanceZone zone, string name) : base(zone, name) { } /// /// 设置产生单位的Force /// /// public void setUnitForce(byte force) { this.mUnitForce = force; } /// /// 设置出生单位名字 /// /// public void setUnitName(string name) { this.mUnitName = name; } /// /// 添加单位模板 /// /// 将要产生的单位模板 public void addItemInfo(int templateID, float percent = 100f) { ItemTemplate info = Zone.Templates.getItem(templateID); if (info != null) { info = (ItemTemplate)info.Clone(); mSpawnUnitTemplates.Add(new SpawnItemInfo(info, percent)); } } /// /// 清除所有怪物模板 /// public void clearTemplates() { mSpawnUnitTemplates.Clear(); } protected override InstanceZoneObject SpawnObject(IPositionObject pos) { InstanceZone zone = this.BindingZone; SpawnItemInfo spawn = mSpawnUnitTemplates[SpawnIndexer % mSpawnUnitTemplates.Count]; if (CUtils.RandomPercent(zone.RandomN, spawn.Percent)) { IVector2 mpos = pos != null ? new TVector2(pos.X, pos.Y) : BindingRegion.getRandomPos(zone.RandomN); float direction = pos != null ? pos.Direction : base.StartDirection; ItemTemplate info = spawn.Item; info = (ItemTemplate)info.Clone(); InstanceItem item = zone.AddItem(info, mUnitName, mpos.X, mpos.Y, direction, mUnitForce, mUnitName, null); return item; } return null; } protected override void OnObjectSpawned(InstanceZoneObject obj) { } protected override void OnSpawnedObjectRemoved(InstanceZoneObject obj) { } } }