Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / map / preinstall / RoomPreinstall.cs
@小李xl 小李xl on 23 Mar 2024 17 KB 制作商店中
  1.  
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using Config;
  6. using Godot;
  7.  
  8. /// <summary>
  9. /// 房间预设处理类
  10. /// </summary>
  11. public class RoomPreinstall : IDestroy
  12. {
  13. public bool IsDestroyed { get; private set; }
  14.  
  15. /// <summary>
  16. /// 所属房间对象
  17. /// </summary>
  18. public RoomInfo RoomInfo { get; }
  19. /// <summary>
  20. /// 绑定的预设数据
  21. /// </summary>
  22. public RoomPreinstallInfo RoomPreinstallInfo { get; }
  23.  
  24. /// <summary>
  25. /// 总波数
  26. /// </summary>
  27. public int WaveCount => RoomPreinstallInfo.WaveList.Count;
  28.  
  29. /// <summary>
  30. /// 波数和标记数据列表
  31. /// </summary>
  32. public List<List<ActivityMark>> WaveList { get; } = new List<List<ActivityMark>>();
  33.  
  34. /// <summary>
  35. /// 是否正在执行生成波数操作
  36. /// </summary>
  37. public bool IsRunWave { get; private set; }
  38.  
  39. /// <summary>
  40. /// 是否执行到最后一波了
  41. /// </summary>
  42. public bool IsLastWave => _currWaveIndex >= WaveList.Count;
  43. //是否运行过预处理
  44. private bool _runPretreatment = false;
  45. //当前房间是否会刷新敌人
  46. private bool _hsaEnemy = false;
  47. //当前波数索引
  48. private int _currWaveIndex = 0;
  49. //执行生成标记的协程id
  50. private long _coroutineId = -1;
  51. //提前加载列表
  52. private List<PreloadData> _readyList;
  53.  
  54. private class PreloadData
  55. {
  56. /// <summary>
  57. /// 实例对象
  58. /// </summary>
  59. public ActivityObject ActivityObject;
  60. /// <summary>
  61. /// 所在层级
  62. /// </summary>
  63. public RoomLayerEnum Layer;
  64.  
  65. public PreloadData(ActivityObject activityObject, RoomLayerEnum layer)
  66. {
  67. ActivityObject = activityObject;
  68. Layer = layer;
  69. }
  70. }
  71.  
  72. public RoomPreinstall(RoomInfo roomInfo, RoomPreinstallInfo roomPreinstallInfo)
  73. {
  74. RoomInfo = roomInfo;
  75. RoomPreinstallInfo = roomPreinstallInfo;
  76. }
  77.  
  78. /// <summary>
  79. /// 预处理操作
  80. /// </summary>
  81. public void Pretreatment(World world)
  82. {
  83. if (_runPretreatment)
  84. {
  85. return;
  86. }
  87.  
  88. _runPretreatment = true;
  89.  
  90. //确定房间内要生成写啥
  91. foreach (var markInfos in RoomPreinstallInfo.WaveList)
  92. {
  93. var wave = new List<ActivityMark>();
  94. WaveList.Add(wave);
  95. foreach (var markInfo in markInfos)
  96. {
  97. var mark = new ActivityMark();
  98. if (markInfo.SpecialMarkType == SpecialMarkType.Normal) //普通标记
  99. {
  100. if (HandlerNormalMark(world, markInfo, mark)) continue;
  101. }
  102. else if (markInfo.SpecialMarkType == SpecialMarkType.BirthPoint) //玩家出生标记
  103. {
  104. }
  105. else if (markInfo.SpecialMarkType == SpecialMarkType.OutPoint) //出口标记
  106. {
  107. }
  108. else if (markInfo.SpecialMarkType == SpecialMarkType.ShopBoss) //商店老板标记
  109. {
  110. HandlerShopBossMark(world, markInfo, mark);
  111. }
  112. else if (markInfo.SpecialMarkType == SpecialMarkType.Treasure) //奖励宝箱标记
  113. {
  114. HandlerTreasureMark(world, markInfo, mark);
  115. }
  116. else
  117. {
  118. Debug.LogError("暂未支持的类型: " + markInfo.SpecialMarkType);
  119. continue;
  120. }
  121.  
  122. mark.DelayTime = markInfo.DelayTime;
  123. mark.MarkType = markInfo.SpecialMarkType;
  124. //随机刷新坐标
  125. var pos = markInfo.Position.AsVector2();
  126. var birthRect = markInfo.Size.AsVector2();
  127. var tempPos = new Vector2(
  128. world.Random.RandomRangeInt((int)(pos.X - birthRect.X / 2), (int)(pos.X + birthRect.X / 2)),
  129. world.Random.RandomRangeInt((int)(pos.Y - birthRect.Y / 2), (int)(pos.Y + birthRect.Y / 2))
  130. );
  131. mark.Position = RoomInfo.ToGlobalPosition(tempPos);
  132. wave.Add(mark);
  133. }
  134. }
  135. //自动填充操作
  136. if (RoomPreinstallInfo.AutoFill)
  137. {
  138. world.RandomPool.FillAutoWave(this);
  139. }
  140. //排序操作
  141. foreach (var wave in WaveList)
  142. {
  143. wave.Sort((a, b) => (int)(a.DelayTime * 1000 - b.DelayTime * 1000));
  144. }
  145. //判断是否有敌人
  146. CheckHasEnemy();
  147. }
  148.  
  149. private static bool HandlerNormalMark(World world, MarkInfo markInfo, ActivityMark mark)
  150. {
  151. MarkInfoItem markInfoItem;
  152. if (markInfo.MarkList.Count == 0) //未配置生成的物体
  153. {
  154. return true;
  155. }
  156. else if (markInfo.MarkList.Count == 1)
  157. {
  158. markInfoItem = markInfo.MarkList[0];
  159. }
  160. else
  161. {
  162. var tempArray = markInfo.MarkList.Select(item => item.Weight).ToArray();
  163. var index = world.Random.RandomWeight(tempArray);
  164. markInfoItem = markInfo.MarkList[index];
  165. }
  166. var activityBase = PreinstallMarkManager.GetMarkConfig(markInfoItem.Id);
  167. mark.Attr = markInfoItem.Attr;
  168. mark.VerticalSpeed = markInfoItem.VerticalSpeed;
  169. mark.Altitude = markInfoItem.Altitude;
  170. if (activityBase is RandomActivityBase) //随机物体
  171. {
  172. if (markInfoItem.Id == PreinstallMarkManager.RandomWeapon.Id) //随机武器
  173. {
  174. mark.Id = world.RandomPool.GetRandomWeapon()?.Id;
  175. mark.ActivityType = ActivityType.Weapon;
  176. }
  177. else if (markInfoItem.Id == PreinstallMarkManager.RandomEnemy.Id) //随机敌人
  178. {
  179. mark.Id = world.RandomPool.GetRandomEnemy()?.Id;
  180. mark.ActivityType = ActivityType.Enemy;
  181. }
  182. else if (markInfoItem.Id == PreinstallMarkManager.RandomProp.Id) //随机道具
  183. {
  184. mark.Id = world.RandomPool.GetRandomProp()?.Id;
  185. mark.ActivityType = ActivityType.Prop;
  186. }
  187. else //非随机物体
  188. {
  189. Debug.LogError("未知的随机物体:" + markInfoItem.Id);
  190. return true;
  191. }
  192. }
  193. else
  194. {
  195. mark.Id = markInfoItem.Id;
  196. mark.ActivityType = (ActivityType)activityBase.Type;
  197. if (mark.ActivityType == ActivityType.Enemy) //敌人类型
  198. {
  199. mark.DerivedAttr = new Dictionary<string, string>();
  200. if (!mark.Attr.TryGetValue("Face", out var face) || face == "0") //随机方向
  201. {
  202. mark.DerivedAttr.Add("Face",
  203. world.Random.RandomChoose(
  204. ((int)FaceDirection.Left).ToString(),
  205. ((int)FaceDirection.Right).ToString()
  206. )
  207. );
  208. }
  209. else //指定方向
  210. {
  211. mark.DerivedAttr.Add("Face", face);
  212. }
  213. }
  214. }
  215.  
  216. return false;
  217. }
  218. private void HandlerShopBossMark(World world, MarkInfo markInfo, ActivityMark mark)
  219. {
  220. mark.Id = ActivityObject.Ids.Id_treasure_box0001;
  221. mark.ActivityType = ActivityType.Treasure;
  222. mark.Altitude = 0;
  223. }
  224. private void HandlerTreasureMark(World world, MarkInfo markInfo, ActivityMark mark)
  225. {
  226. mark.Id = ActivityObject.Ids.Id_treasure_box0001;
  227. mark.ActivityType = ActivityType.Treasure;
  228. mark.Altitude = 0;
  229. }
  230.  
  231. private void CheckHasEnemy()
  232. {
  233. foreach (var marks in WaveList)
  234. {
  235. foreach (var activityMark in marks)
  236. {
  237. if (activityMark.ActivityType == ActivityType.Enemy)
  238. {
  239. _hsaEnemy = true;
  240. return;
  241. }
  242. }
  243. }
  244. }
  245.  
  246. /// <summary>
  247. /// 预处理后才可以调用, 返回是否会生成敌人
  248. /// </summary>
  249. public bool HasEnemy()
  250. {
  251. return _hsaEnemy;
  252. }
  253. /// <summary>
  254. /// 地牢房间加载完成
  255. /// </summary>
  256. public void OnReady()
  257. {
  258. _currWaveIndex = 0;
  259. //加载提前生成的物体
  260. if (WaveList.Count > 0)
  261. {
  262. var activityMarks = WaveList[0];
  263. foreach (var activityMark in activityMarks)
  264. {
  265. if (activityMark.MarkType == SpecialMarkType.Normal ||
  266. activityMark.MarkType == SpecialMarkType.Treasure ||
  267. activityMark.MarkType == SpecialMarkType.ShopBoss)
  268. {
  269. var activityObject = CreateItem(activityMark);
  270. if (activityObject == null)
  271. {
  272. continue;
  273. }
  274. //初始化属性
  275. InitAttr(activityObject, activityMark);
  276. if (_readyList == null)
  277. {
  278. _readyList = new List<PreloadData>();
  279. }
  280. _readyList.Add(new PreloadData(activityObject, GetDefaultLayer(activityMark)));
  281. activityObject.OnCreateWithMark(this, activityMark);
  282. }
  283. }
  284. }
  285.  
  286. _currWaveIndex++;
  287. }
  288.  
  289. /// <summary>
  290. /// 玩家进入房间, 开始执行生成物体
  291. /// </summary>
  292. public void StartWave()
  293. {
  294. if (IsRunWave)
  295. {
  296. return;
  297. }
  298.  
  299. IsRunWave = true;
  300.  
  301. _currWaveIndex = 1;
  302. //判断房间内是否已经有敌人了
  303. var hasEnemy = false;
  304. if (_readyList != null && _readyList.Count > 0)
  305. {
  306. foreach (var preloadData in _readyList)
  307. {
  308. //有敌人
  309. if (!hasEnemy && preloadData.ActivityObject.CollisionWithMask(PhysicsLayer.Enemy))
  310. {
  311. hasEnemy = true;
  312. }
  313.  
  314. preloadData.ActivityObject.PutDown(preloadData.Layer);
  315. }
  316.  
  317. _readyList.Clear();
  318. _readyList = null;
  319. }
  320.  
  321. if (!hasEnemy)
  322. {
  323. hasEnemy = RoomInfo.AffiliationArea.ExistIncludeItem(
  324. activityObject => activityObject.CollisionWithMask(PhysicsLayer.Enemy)
  325. );
  326. }
  327.  
  328. if (!hasEnemy) //没有敌人才能执行第1波
  329. {
  330. if (_currWaveIndex < WaveList.Count)
  331. {
  332. Debug.Log($"执行第{_currWaveIndex}波");
  333. _coroutineId = World.Current.StartCoroutine(RunMark(WaveList[_currWaveIndex]));
  334. _currWaveIndex++;
  335. }
  336. }
  337. }
  338.  
  339. /// <summary>
  340. /// 执行下一波
  341. /// </summary>
  342. public void NextWave()
  343. {
  344. if (!IsRunWave)
  345. {
  346. return;
  347. }
  348. Debug.Log($"执行第{_currWaveIndex}波");
  349. _coroutineId = World.Current.StartCoroutine(RunMark(WaveList[_currWaveIndex]));
  350. _currWaveIndex++;
  351. }
  352.  
  353. /// <summary>
  354. /// 结束生成标记
  355. /// </summary>
  356. public void OverWave()
  357. {
  358. IsRunWave = false;
  359. }
  360. //执行实例化标记物体
  361. private IEnumerator RunMark(List<ActivityMark> activityMarks)
  362. {
  363. var timer = 0d;
  364. for (var i = 0; i < activityMarks.Count;)
  365. {
  366. var activityMark = activityMarks[i];
  367. if (timer >= activityMark.DelayTime)
  368. {
  369. if (activityMark.MarkType == SpecialMarkType.Normal)
  370. {
  371. var activityObject = CreateItem(activityMark);
  372. //初始化属性
  373. InitAttr(activityObject, activityMark);
  374. //播放出生动画
  375. activityObject.StartCoroutine(OnActivityObjectBirth(activityObject));
  376. activityObject.PutDown(GetDefaultLayer(activityMark));
  377. activityObject.UpdateFall((float)GameApplication.Instance.GetProcessDeltaTime());
  378.  
  379. if (activityObject is Enemy enemy)
  380. {
  381. //出生调用
  382. enemy.OnBornFromMark();
  383. }
  384. var effect = ObjectManager.GetPoolItem<IEffect>(ResourcePath.prefab_effect_common_Effect1_tscn);
  385. var node = (Node2D)effect;
  386. node.Position = activityObject.Position + new Vector2(0, -activityMark.Altitude);
  387. node.AddToActivityRoot(RoomLayerEnum.YSortLayer);
  388. effect.PlayEffect();
  389. }
  390. i++;
  391. }
  392. else
  393. {
  394. timer += GameApplication.Instance.GetProcessDeltaTime();
  395. yield return 0;
  396. }
  397. }
  398.  
  399. _coroutineId = -1;
  400. }
  401.  
  402. //生成 ActivityObject 时调用, 用于出生时的动画效果
  403. private IEnumerator OnActivityObjectBirth(ActivityObject instance)
  404. {
  405. var a = 1.0f;
  406. instance.SetBlendColor(Colors.White);
  407. //禁用自定义行为
  408. instance.EnableCustomBehavior = false;
  409. //禁用下坠
  410. instance.EnableVerticalMotion = false;
  411.  
  412. instance.SetBlendSchedule(a);
  413. yield return new WaitForFixedProcess(10);
  414.  
  415. while (a > 0)
  416. {
  417. instance.SetBlendSchedule(a);
  418. a -= 0.05f;
  419. yield return 0;
  420. }
  421. instance.SetBlendSchedule(0);
  422.  
  423. //启用自定义行为
  424. instance.EnableCustomBehavior = true;
  425. //启用下坠
  426. instance.EnableVerticalMotion = true;
  427. }
  428.  
  429. /// <summary>
  430. /// 当前这一波是否执行完成
  431. /// </summary>
  432. public bool IsCurrWaveOver()
  433. {
  434. return _coroutineId < 0 || World.Current.IsCoroutineOver(_coroutineId);
  435. }
  436. //创建物体
  437. private ActivityObject CreateItem(ActivityMark activityMark)
  438. {
  439. var activityObject = ActivityObject.Create(activityMark.Id);
  440. if (activityObject == null)
  441. {
  442. return null;
  443. }
  444. activityObject.Position = activityMark.Position;
  445. activityObject.VerticalSpeed = activityMark.VerticalSpeed;
  446. activityObject.Altitude = activityMark.Altitude;
  447. return activityObject;
  448. }
  449.  
  450. //获取物体默认所在层级
  451. private RoomLayerEnum GetDefaultLayer(ActivityMark activityMark)
  452. {
  453. if (activityMark.ActivityType == ActivityType.Player || activityMark.ActivityType == ActivityType.Enemy || activityMark.ActivityType == ActivityType.Treasure)
  454. {
  455. return RoomLayerEnum.YSortLayer;
  456. }
  457.  
  458. return RoomLayerEnum.NormalLayer;
  459. }
  460. /// <summary>
  461. /// 获取房间内的特殊标记
  462. /// </summary>
  463. public ActivityMark GetSpecialMark(SpecialMarkType specialMarkType)
  464. {
  465. if (WaveList.Count == 0)
  466. {
  467. return null;
  468. }
  469.  
  470. var activityMarks = WaveList[0];
  471. var activityMark = activityMarks.FirstOrDefault(mark => mark.MarkType == specialMarkType);
  472. return activityMark;
  473. }
  474.  
  475. public void Destroy()
  476. {
  477. if (IsDestroyed)
  478. {
  479. return;
  480. }
  481.  
  482. IsDestroyed = true;
  483. if (_coroutineId >= 0)
  484. {
  485. World.Current.StopCoroutine(_coroutineId);
  486. }
  487.  
  488. WaveList.Clear();
  489. if (_readyList != null)
  490. {
  491. foreach (var preloadData in _readyList)
  492. {
  493. preloadData.ActivityObject.Destroy();
  494. }
  495.  
  496. _readyList.Clear();
  497. }
  498. }
  499. /// <summary>
  500. /// 获取或创建指定波数数据
  501. /// </summary>
  502. public List<ActivityMark> GetOrCreateWave(int waveIndex)
  503. {
  504. while (WaveList.Count <= waveIndex)
  505. {
  506. WaveList.Add(new List<ActivityMark>());
  507. }
  508. return WaveList[waveIndex];
  509. }
  510.  
  511. //初始化物体属性
  512. private void InitAttr(ActivityObject activityObject, ActivityMark activityMark)
  513. {
  514. if (activityMark.Attr == null)
  515. {
  516. return;
  517. }
  518. if (activityMark.ActivityType == ActivityType.Weapon) //武器类型
  519. {
  520. var weapon = (Weapon)activityObject;
  521. if (activityMark.Attr.TryGetValue("CurrAmmon", out var currAmmon)) //当前弹夹弹药
  522. {
  523. weapon.SetCurrAmmo(int.Parse(currAmmon));
  524. }
  525. if (activityMark.Attr.TryGetValue("ResidueAmmo", out var residueAmmo)) //剩余弹药
  526. {
  527. weapon.SetResidueAmmo(int.Parse(residueAmmo));
  528. }
  529. }
  530. else if (activityMark.ActivityType == ActivityType.Enemy) //敌人类型
  531. {
  532. var role = (Role)activityObject;
  533. if (role.WeaponPack.Capacity > 0 && role is Enemy enemy && activityMark.Attr.TryGetValue("Weapon", out var weaponId)) //使用的武器
  534. {
  535. if (!string.IsNullOrEmpty(weaponId))
  536. {
  537. var weapon = ActivityObject.Create<Weapon>(weaponId);
  538. enemy.PickUpWeapon(weapon);
  539. if (activityMark.Attr.TryGetValue("CurrAmmon", out var currAmmon)) //当前弹夹弹药
  540. {
  541. weapon.SetCurrAmmo(int.Parse(currAmmon));
  542. }
  543. if (activityMark.Attr.TryGetValue("ResidueAmmo", out var residueAmmo)) //剩余弹药
  544. {
  545. weapon.SetResidueAmmo(int.Parse(residueAmmo));
  546. }
  547. }
  548. }
  549.  
  550. if (activityMark.DerivedAttr != null && activityMark.DerivedAttr.TryGetValue("Face", out var face)) //脸朝向, 应该只有 -1 和 1
  551. {
  552. var faceDir = int.Parse(face);
  553. role.Face = (FaceDirection)faceDir;
  554. }
  555. }
  556. }
  557. }