using System.Collections; using System.Collections.Generic; using System.Linq; using Config; using Godot; /// <summary> /// 房间预设处理类 /// </summary> public class RoomPreinstall : IDestroy { public bool IsDestroyed { get; private set; } /// <summary> /// 所属房间对象 /// </summary> public RoomInfo RoomInfo { get; } /// <summary> /// 绑定的预设数据 /// </summary> public RoomPreinstallInfo RoomPreinstallInfo { get; } /// <summary> /// 总波数 /// </summary> public int WaveCount => RoomPreinstallInfo.WaveList.Count; /// <summary> /// 波数和标记数据列表 /// </summary> public List<List<ActivityMark>> WaveList { get; } = new List<List<ActivityMark>>(); /// <summary> /// 是否正在执行生成波数操作 /// </summary> public bool IsRunWave { get; private set; } /// <summary> /// 是否执行到最后一波了 /// </summary> public bool IsLastWave => _currWaveIndex >= WaveList.Count; /// <summary> /// 包含的 Boss 列表 /// </summary> public List<Boss> BossList { get; } = new List<Boss>(); //是否运行过预处理 private bool _runPretreatment = false; //当前房间是否会刷新敌人 private bool _hsaEnemy = false; //当前波数索引 private int _currWaveIndex = 0; //执行生成标记的协程id private long _coroutineId = -1; //提前加载列表 private List<PreloadData> _readyList; private class PreloadData { /// <summary> /// 实例对象 /// </summary> public ActivityObject ActivityObject; /// <summary> /// 所在层级 /// </summary> public RoomLayerEnum Layer; public PreloadData(ActivityObject activityObject, RoomLayerEnum layer) { ActivityObject = activityObject; Layer = layer; } } public RoomPreinstall(RoomInfo roomInfo, RoomPreinstallInfo roomPreinstallInfo) { RoomInfo = roomInfo; RoomPreinstallInfo = roomPreinstallInfo; } /// <summary> /// 预处理操作 /// </summary> public void Pretreatment(World world) { if (_runPretreatment) { return; } _runPretreatment = true; //确定房间内要生成写啥 foreach (var markInfos in RoomPreinstallInfo.WaveList) { var wave = new List<ActivityMark>(); WaveList.Add(wave); foreach (var markInfo in markInfos) { var mark = new ActivityMark(); if (markInfo.SpecialMarkType == SpecialMarkType.Normal) //普通标记 { if (HandlerNormalMark(world, markInfo, mark)) continue; } else if (markInfo.SpecialMarkType == SpecialMarkType.BirthPoint) //玩家出生标记 { } else if (markInfo.SpecialMarkType == SpecialMarkType.OutPoint) //出口标记 { HandlerOutPointMark(world, markInfo, mark); } else if (markInfo.SpecialMarkType == SpecialMarkType.ShopBoss) //商店老板标记 { HandlerShopBossMark(world, markInfo, mark); } else if (markInfo.SpecialMarkType == SpecialMarkType.Treasure) //奖励宝箱标记 { HandlerTreasureMark(world, markInfo, mark); } else if (markInfo.SpecialMarkType == SpecialMarkType.Boss) //Boss标记 { HandlerBossMark(world, markInfo, mark); } else { Debug.LogError("暂未支持的类型: " + markInfo.SpecialMarkType); continue; } mark.DelayTime = markInfo.DelayTime; mark.MarkType = markInfo.SpecialMarkType; //随机刷新坐标 var pos = markInfo.Position.AsVector2(); var birthRect = markInfo.Size.AsVector2(); var tempPos = new Vector2( world.Random.RandomRangeInt((int)(pos.X - birthRect.X / 2), (int)(pos.X + birthRect.X / 2)), world.Random.RandomRangeInt((int)(pos.Y - birthRect.Y / 2), (int)(pos.Y + birthRect.Y / 2)) ); mark.Position = RoomInfo.ToGlobalPosition(tempPos); wave.Add(mark); } } //自动填充操作 if (RoomPreinstallInfo.AutoFill) { world.RandomPool.FillAutoWave(this); } //排序操作 foreach (var wave in WaveList) { wave.Sort((a, b) => (int)(a.DelayTime * 1000 - b.DelayTime * 1000)); } //判断是否有敌人 CheckHasEnemy(); } private static bool HandlerNormalMark(World world, MarkInfo markInfo, ActivityMark mark) { MarkInfoItem markInfoItem; if (markInfo.MarkList.Count == 0) //未配置生成的物体 { return true; } else if (markInfo.MarkList.Count == 1) { markInfoItem = markInfo.MarkList[0]; } else { var tempArray = markInfo.MarkList.Select(item => item.Weight).ToArray(); var index = world.Random.RandomWeight(tempArray); markInfoItem = markInfo.MarkList[index]; } var activityBase = PreinstallMarkManager.GetMarkConfig(markInfoItem.Id); mark.Attr = markInfoItem.Attr; mark.VerticalSpeed = markInfoItem.VerticalSpeed; mark.Altitude = markInfoItem.Altitude; if (activityBase is RandomActivityBase) //随机物体 { if (markInfoItem.Id == PreinstallMarkManager.RandomWeapon.Id) //随机武器 { mark.Id = world.RandomPool.GetRandomWeapon()?.Id; mark.ActivityType = ActivityType.Weapon; } else if (markInfoItem.Id == PreinstallMarkManager.RandomEnemy.Id) //随机敌人 { mark.Id = world.RandomPool.GetRandomEnemy()?.Id; mark.ActivityType = ActivityType.Enemy; } else if (markInfoItem.Id == PreinstallMarkManager.RandomProp.Id) //随机道具 { mark.Id = world.RandomPool.GetRandomProp()?.Id; mark.ActivityType = ActivityType.Prop; } else //非随机物体 { Debug.LogError("未知的随机物体:" + markInfoItem.Id); return true; } } else if (activityBase is MissActivityBase) //丢失物体 { Debug.LogError("丢失物体:" + markInfoItem.Id); return true; } else { mark.Id = markInfoItem.Id; mark.ActivityType = (ActivityType)activityBase.Type; if (mark.ActivityType == ActivityType.Enemy) //敌人类型 { mark.DerivedAttr = new Dictionary<string, string>(); if (!mark.Attr.TryGetValue("Face", out var face) || face == "0") //随机方向 { mark.DerivedAttr.Add("Face", world.Random.RandomChoose( ((int)FaceDirection.Left).ToString(), ((int)FaceDirection.Right).ToString() ) ); } else //指定方向 { mark.DerivedAttr.Add("Face", face); } } } return false; } private void HandlerOutPointMark(World world, MarkInfo markInfo, ActivityMark mark) { mark.OnReadyEvent += () => { var roomExit = ResourceManager.LoadAndInstantiate<RoomExit>(ResourcePath.prefab_room_RoomExit_tscn); roomExit.Position = mark.Position; roomExit.AddToActivityRoot(RoomLayerEnum.NormalLayer); }; } private void HandlerShopBossMark(World world, MarkInfo markInfo, ActivityMark mark) { mark.Id = ActivityObject.Ids.Id_shopBoss0001; mark.ActivityType = ActivityType.Npc; mark.Altitude = 0; } private void HandlerTreasureMark(World world, MarkInfo markInfo, ActivityMark mark) { mark.Id = ActivityObject.Ids.Id_treasure_box0001; mark.ActivityType = ActivityType.Treasure; mark.Altitude = 0; } private void HandlerBossMark(World world, MarkInfo markInfo, ActivityMark mark) { mark.Id = ActivityObject.Ids.Id_boss0001; mark.ActivityType = ActivityType.Boss; mark.Altitude = 0; } private void CheckHasEnemy() { foreach (var marks in WaveList) { foreach (var activityMark in marks) { if (activityMark.ActivityType == ActivityType.Enemy || activityMark.ActivityType == ActivityType.Boss) { _hsaEnemy = true; return; } } } } /// <summary> /// 预处理后才可以调用, 返回是否会生成敌人 /// </summary> public bool HasEnemy() { return _hsaEnemy; } /// <summary> /// 地牢房间加载完成 /// </summary> public void OnReady() { _currWaveIndex = 0; //加载提前生成的物体 if (WaveList.Count > 0) { var activityMarks = WaveList[0]; foreach (var activityMark in activityMarks) { var activityObject = CreateItem(activityMark); if (activityObject != null) { //初始化属性 InitAttr(activityObject, activityMark); if (_readyList == null) { _readyList = new List<PreloadData>(); } _readyList.Add(new PreloadData(activityObject, GetDefaultLayer(activityMark))); activityObject.OnCreateWithMark(this, activityMark); if (activityObject is Boss boss) { BossList.Add(boss); } } if (activityMark.OnReadyEvent != null) { activityMark.OnReadyEvent(); } } } _currWaveIndex++; } /// <summary> /// 玩家进入房间, 开始执行生成物体 /// </summary> public void StartWave() { if (IsRunWave) { return; } IsRunWave = true; _currWaveIndex = 1; //判断房间内是否已经有敌人了 var hasEnemy = false; if (_readyList != null && _readyList.Count > 0) { foreach (var preloadData in _readyList) { //有敌人 var activityObject = preloadData.ActivityObject; if (!hasEnemy && activityObject is Role role && role.IsEnemyWithPlayer()) { hasEnemy = true; } //临时处理 //播放出生动画 activityObject.PutDown(preloadData.Layer); if (activityObject is not Boss) { activityObject.StartCoroutine(OnActivityObjectBirth(activityObject)); activityObject.UpdateFall((float)GameApplication.Instance.GetProcessDeltaTime()); //出生特效 var effect = ObjectManager.GetPoolItem<IEffect>(ResourcePath.prefab_effect_common_Effect1_tscn); var node = (Node2D)effect; node.Position = activityObject.Position + new Vector2(0, -activityObject.Altitude); node.AddToActivityRoot(RoomLayerEnum.YSortLayer); effect.PlayEffect(); } //原本代码 //preloadData.ActivityObject.PutDown(preloadData.Layer); } _readyList.Clear(); _readyList = null; } if (!hasEnemy) { hasEnemy = RoomInfo.AffiliationArea.ExistIncludeItem( activityObject => activityObject is Role role && role.IsEnemyWithPlayer() ); } if (!hasEnemy) //没有敌人才能执行第1波 { if (_currWaveIndex < WaveList.Count) { Debug.Log($"执行第{_currWaveIndex}波"); _coroutineId = World.Current.StartCoroutine(RunMark(WaveList[_currWaveIndex])); _currWaveIndex++; } } } /// <summary> /// 执行下一波 /// </summary> public void NextWave() { if (!IsRunWave) { return; } Debug.Log($"执行第{_currWaveIndex}波"); _coroutineId = World.Current.StartCoroutine(RunMark(WaveList[_currWaveIndex])); _currWaveIndex++; } /// <summary> /// 结束生成标记 /// </summary> public void OverWave() { IsRunWave = false; } //执行实例化标记物体 private IEnumerator RunMark(List<ActivityMark> activityMarks) { var timer = 0d; for (var i = 0; i < activityMarks.Count;) { var activityMark = activityMarks[i]; if (timer >= activityMark.DelayTime) { if (activityMark.MarkType == SpecialMarkType.Normal) { var activityObject = CreateItem(activityMark); //初始化属性 InitAttr(activityObject, activityMark); //播放出生动画 activityObject.StartCoroutine(OnActivityObjectBirth(activityObject)); activityObject.PutDown(GetDefaultLayer(activityMark)); activityObject.UpdateFall((float)GameApplication.Instance.GetProcessDeltaTime()); if (activityObject is Enemy enemy) { //出生调用 enemy.OnBornFromMark(); } //出生特效 var effect = ObjectManager.GetPoolItem<IEffect>(ResourcePath.prefab_effect_common_Effect1_tscn); var node = (Node2D)effect; node.Position = activityObject.Position + new Vector2(0, -activityMark.Altitude); node.AddToActivityRoot(RoomLayerEnum.YSortLayer); effect.PlayEffect(); } i++; } else { timer += GameApplication.Instance.GetProcessDeltaTime(); yield return 0; } } _coroutineId = -1; } //生成 ActivityObject 时调用, 用于出生时的动画效果 private IEnumerator OnActivityObjectBirth(ActivityObject instance) { var a = 1.0f; instance.SetBlendColor(Colors.White); //禁用自定义行为 instance.EnableCustomBehavior = false; //禁用下坠 instance.EnableVerticalMotion = false; instance.SetBlendSchedule(a); yield return new WaitForFixedProcess(10); while (a > 0) { instance.SetBlendSchedule(a); a -= 0.05f; yield return 0; } instance.SetBlendSchedule(0); //启用自定义行为 instance.EnableCustomBehavior = true; //启用下坠 instance.EnableVerticalMotion = true; } /// <summary> /// 当前这一波是否执行完成 /// </summary> public bool IsCurrWaveOver() { return _coroutineId < 0 || World.Current.IsCoroutineOver(_coroutineId); } //创建物体 private ActivityObject CreateItem(ActivityMark activityMark) { if (string.IsNullOrEmpty(activityMark.Id)) { return null; } var activityObject = ActivityObject.Create(activityMark.Id); if (activityObject == null) { return null; } activityObject.Position = activityMark.Position; activityObject.VerticalSpeed = activityMark.VerticalSpeed; activityObject.Altitude = activityMark.Altitude; return activityObject; } //获取物体默认所在层级 private RoomLayerEnum GetDefaultLayer(ActivityMark activityMark) { switch (activityMark.ActivityType) { case ActivityType.Player: case ActivityType.Enemy: case ActivityType.Npc: case ActivityType.Boss: case ActivityType.Treasure: return RoomLayerEnum.YSortLayer; default: return RoomLayerEnum.NormalLayer; } } /// <summary> /// 获取房间内的特殊标记 /// </summary> public ActivityMark GetSpecialMark(SpecialMarkType specialMarkType) { if (WaveList.Count == 0) { return null; } var activityMarks = WaveList[0]; var activityMark = activityMarks.FirstOrDefault(mark => mark.MarkType == specialMarkType); return activityMark; } public void Destroy() { if (IsDestroyed) { return; } IsDestroyed = true; if (_coroutineId >= 0) { World.Current.StopCoroutine(_coroutineId); } WaveList.Clear(); if (_readyList != null) { foreach (var preloadData in _readyList) { preloadData.ActivityObject.Destroy(); } _readyList.Clear(); } } /// <summary> /// 获取或创建指定波数数据 /// </summary> public List<ActivityMark> GetOrCreateWave(int waveIndex) { while (WaveList.Count <= waveIndex) { WaveList.Add(new List<ActivityMark>()); } return WaveList[waveIndex]; } //初始化物体属性 private void InitAttr(ActivityObject activityObject, ActivityMark activityMark) { if (activityMark.Attr == null) { return; } if (activityMark.ActivityType == ActivityType.Weapon) //武器类型 { var weapon = (Weapon)activityObject; if (activityMark.Attr.TryGetValue("CurrAmmon", out var currAmmon)) //当前弹夹弹药 { weapon.SetCurrAmmo(int.Parse(currAmmon)); } if (activityMark.Attr.TryGetValue("ResidueAmmo", out var residueAmmo)) //剩余弹药 { weapon.SetResidueAmmo(int.Parse(residueAmmo)); } } else if (activityMark.ActivityType == ActivityType.Enemy) //敌人类型 { var role = (Role)activityObject; if (role.WeaponPack.Capacity > 0 && role is Enemy enemy && activityMark.Attr.TryGetValue("Weapon", out var weaponId)) //使用的武器 { if (!string.IsNullOrEmpty(weaponId)) { var weapon = ActivityObject.Create<Weapon>(weaponId); enemy.PickUpWeapon(weapon); if (activityMark.Attr.TryGetValue("CurrAmmon", out var currAmmon)) //当前弹夹弹药 { weapon.SetCurrAmmo(int.Parse(currAmmon)); } if (activityMark.Attr.TryGetValue("ResidueAmmo", out var residueAmmo)) //剩余弹药 { weapon.SetResidueAmmo(int.Parse(residueAmmo)); } } } if (activityMark.DerivedAttr != null && activityMark.DerivedAttr.TryGetValue("Face", out var face)) //脸朝向, 应该只有 -1 和 1 { var faceDir = int.Parse(face); role.Face = (FaceDirection)faceDir; } } } }