Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / map / preinstall / RoomPreinstall.cs
  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. MarkInfoItem markInfoItem;
  101. if (markInfo.MarkList.Count == 0)
  102. {
  103. continue;
  104. }
  105. else if (markInfo.MarkList.Count == 1)
  106. {
  107. markInfoItem = markInfo.MarkList[0];
  108. }
  109. else
  110. {
  111. var tempArray = markInfo.MarkList.Select(item => item.Weight).ToArray();
  112. var index = world.Random.RandomWeight(tempArray);
  113. markInfoItem = markInfo.MarkList[index];
  114. }
  115. var activityBase = PreinstallMarkManager.GetMarkConfig(markInfoItem.Id);
  116. mark.Attr = markInfoItem.Attr;
  117. mark.VerticalSpeed = markInfoItem.VerticalSpeed;
  118. mark.Altitude = markInfoItem.Altitude;
  119. if (activityBase is RandomActivityBase) //随机物体
  120. {
  121. if (markInfoItem.Id == PreinstallMarkManager.RandomWeapon.Id) //随机武器
  122. {
  123. mark.Id = world.RandomPool.GetRandomWeapon()?.Id;
  124. mark.ActivityType = ActivityType.Weapon;
  125. }
  126. else if (markInfoItem.Id == PreinstallMarkManager.RandomEnemy.Id) //随机敌人
  127. {
  128. mark.Id = world.RandomPool.GetRandomEnemy()?.Id;
  129. mark.ActivityType = ActivityType.Enemy;
  130. }
  131. else if (markInfoItem.Id == PreinstallMarkManager.RandomProp.Id) //随机道具
  132. {
  133. mark.Id = world.RandomPool.GetRandomProp()?.Id;
  134. mark.ActivityType = ActivityType.Prop;
  135. }
  136. else //非随机物体
  137. {
  138. Debug.LogError("未知的随机物体:" + markInfoItem.Id);
  139. continue;
  140. }
  141. }
  142. else
  143. {
  144. mark.Id = markInfoItem.Id;
  145. mark.ActivityType = (ActivityType)activityBase.Type;
  146. if (mark.ActivityType == ActivityType.Enemy) //敌人类型
  147. {
  148. mark.DerivedAttr = new Dictionary<string, string>();
  149. if (!mark.Attr.TryGetValue("Face", out var face) || face == "0") //随机方向
  150. {
  151. mark.DerivedAttr.Add("Face",
  152. world.Random.RandomChoose(
  153. ((int)FaceDirection.Left).ToString(),
  154. ((int)FaceDirection.Right).ToString()
  155. )
  156. );
  157. }
  158. else //指定方向
  159. {
  160. mark.DerivedAttr.Add("Face", face);
  161. }
  162. }
  163. }
  164. }
  165. else if (markInfo.SpecialMarkType == SpecialMarkType.BirthPoint) //玩家出生标记
  166. {
  167. }
  168. else if (markInfo.SpecialMarkType == SpecialMarkType.OutPoint) //出口标记
  169. {
  170.  
  171. }
  172. else
  173. {
  174. Debug.LogError("暂未支持的类型: " + markInfo.SpecialMarkType);
  175. continue;
  176. }
  177.  
  178. mark.DelayTime = markInfo.DelayTime;
  179. mark.MarkType = markInfo.SpecialMarkType;
  180. //随机刷新坐标
  181. var pos = markInfo.Position.AsVector2();
  182. var birthRect = markInfo.Size.AsVector2();
  183. var tempPos = new Vector2(
  184. world.Random.RandomRangeInt((int)(pos.X - birthRect.X / 2), (int)(pos.X + birthRect.X / 2)),
  185. world.Random.RandomRangeInt((int)(pos.Y - birthRect.Y / 2), (int)(pos.Y + birthRect.Y / 2))
  186. );
  187. mark.Position = RoomInfo.ToGlobalPosition(tempPos);
  188. wave.Add(mark);
  189. }
  190. }
  191. //自动填充操作
  192. if (RoomPreinstallInfo.AutoFill)
  193. {
  194. world.RandomPool.FillAutoWave(this);
  195. }
  196. //排序操作
  197. foreach (var wave in WaveList)
  198. {
  199. wave.Sort((a, b) => (int)(a.DelayTime * 1000 - b.DelayTime * 1000));
  200. }
  201. //判断是否有敌人
  202. CheckHasEnemy();
  203. }
  204.  
  205. private void CheckHasEnemy()
  206. {
  207. foreach (var marks in WaveList)
  208. {
  209. foreach (var activityMark in marks)
  210. {
  211. if (activityMark.ActivityType == ActivityType.Enemy)
  212. {
  213. _hsaEnemy = true;
  214. return;
  215. }
  216. }
  217. }
  218. }
  219.  
  220. /// <summary>
  221. /// 预处理后才可以调用, 返回是否会生成敌人
  222. /// </summary>
  223. public bool HasEnemy()
  224. {
  225. return _hsaEnemy;
  226. }
  227. /// <summary>
  228. /// 地牢房间加载完成
  229. /// </summary>
  230. public void OnReady()
  231. {
  232. _currWaveIndex = 0;
  233. //加载提前生成的物体
  234. if (WaveList.Count > 0)
  235. {
  236. var activityMarks = WaveList[0];
  237. foreach (var activityMark in activityMarks)
  238. {
  239. if (activityMark.MarkType == SpecialMarkType.Normal)
  240. {
  241. var activityObject = CreateItem(activityMark);
  242. //初始化属性
  243. InitAttr(activityObject, activityMark);
  244. if (_readyList == null)
  245. {
  246. _readyList = new List<PreloadData>();
  247. }
  248. _readyList.Add(new PreloadData(activityObject, GetDefaultLayer(activityMark)));
  249. }
  250. }
  251. }
  252.  
  253. _currWaveIndex++;
  254. }
  255.  
  256. /// <summary>
  257. /// 玩家进入房间, 开始执行生成物体
  258. /// </summary>
  259. public void StartWave()
  260. {
  261. if (IsRunWave)
  262. {
  263. return;
  264. }
  265.  
  266. IsRunWave = true;
  267.  
  268. _currWaveIndex = 1;
  269. //判断房间内是否已经有敌人了
  270. var hasEnemy = false;
  271. if (_readyList != null && _readyList.Count > 0)
  272. {
  273. foreach (var preloadData in _readyList)
  274. {
  275. //有敌人
  276. if (!hasEnemy && preloadData.ActivityObject.CollisionWithMask(PhysicsLayer.Enemy))
  277. {
  278. hasEnemy = true;
  279. }
  280.  
  281. preloadData.ActivityObject.PutDown(preloadData.Layer);
  282. }
  283.  
  284. _readyList.Clear();
  285. _readyList = null;
  286. }
  287.  
  288. if (!hasEnemy)
  289. {
  290. hasEnemy = RoomInfo.AffiliationArea.ExistIncludeItem(
  291. activityObject => activityObject.CollisionWithMask(PhysicsLayer.Enemy)
  292. );
  293. }
  294.  
  295. if (!hasEnemy) //没有敌人才能执行第1波
  296. {
  297. if (_currWaveIndex < WaveList.Count)
  298. {
  299. Debug.Log($"执行第{_currWaveIndex}波");
  300. _coroutineId = World.Current.StartCoroutine(RunMark(WaveList[_currWaveIndex]));
  301. _currWaveIndex++;
  302. }
  303. }
  304. }
  305.  
  306. /// <summary>
  307. /// 执行下一波
  308. /// </summary>
  309. public void NextWave()
  310. {
  311. if (!IsRunWave)
  312. {
  313. return;
  314. }
  315. Debug.Log($"执行第{_currWaveIndex}波");
  316. _coroutineId = World.Current.StartCoroutine(RunMark(WaveList[_currWaveIndex]));
  317. _currWaveIndex++;
  318. }
  319.  
  320. /// <summary>
  321. /// 结束生成标记
  322. /// </summary>
  323. public void OverWave()
  324. {
  325. IsRunWave = false;
  326. }
  327. //执行实例化标记物体
  328. private IEnumerator RunMark(List<ActivityMark> activityMarks)
  329. {
  330. var timer = 0d;
  331. for (var i = 0; i < activityMarks.Count;)
  332. {
  333. var activityMark = activityMarks[i];
  334. if (timer >= activityMark.DelayTime)
  335. {
  336. if (activityMark.MarkType == SpecialMarkType.Normal)
  337. {
  338. var activityObject = CreateItem(activityMark);
  339. //初始化属性
  340. InitAttr(activityObject, activityMark);
  341. //播放出生动画
  342. activityObject.StartCoroutine(OnActivityObjectBirth(activityObject));
  343. activityObject.PutDown(GetDefaultLayer(activityMark));
  344. activityObject.UpdateFall((float)GameApplication.Instance.GetProcessDeltaTime());
  345.  
  346. if (activityObject is Enemy enemy)
  347. {
  348. //出生调用
  349. enemy.OnBornFromMark();
  350. }
  351. var effect = ObjectManager.GetPoolItem<IEffect>(ResourcePath.prefab_effect_common_Effect1_tscn);
  352. var node = (Node2D)effect;
  353. node.Position = activityObject.Position + new Vector2(0, -activityMark.Altitude);
  354. node.AddToActivityRoot(RoomLayerEnum.YSortLayer);
  355. effect.PlayEffect();
  356. }
  357. i++;
  358. }
  359. else
  360. {
  361. timer += GameApplication.Instance.GetProcessDeltaTime();
  362. yield return 0;
  363. }
  364. }
  365.  
  366. _coroutineId = -1;
  367. }
  368.  
  369. //生成 ActivityObject 时调用, 用于出生时的动画效果
  370. private IEnumerator OnActivityObjectBirth(ActivityObject instance)
  371. {
  372. var a = 1.0f;
  373. instance.SetBlendColor(Colors.White);
  374. //禁用自定义行为
  375. instance.EnableCustomBehavior = false;
  376. //禁用下坠
  377. instance.EnableVerticalMotion = false;
  378.  
  379. instance.SetBlendSchedule(a);
  380. yield return new WaitForFixedProcess(10);
  381.  
  382. while (a > 0)
  383. {
  384. instance.SetBlendSchedule(a);
  385. a -= 0.05f;
  386. yield return 0;
  387. }
  388. instance.SetBlendSchedule(0);
  389.  
  390. //启用自定义行为
  391. instance.EnableCustomBehavior = true;
  392. //启用下坠
  393. instance.EnableVerticalMotion = true;
  394. }
  395.  
  396. /// <summary>
  397. /// 当前这一波是否执行完成
  398. /// </summary>
  399. public bool IsCurrWaveOver()
  400. {
  401. return _coroutineId < 0 || World.Current.IsCoroutineOver(_coroutineId);
  402. }
  403. //创建物体
  404. private ActivityObject CreateItem(ActivityMark activityMark)
  405. {
  406. var activityObject = ActivityObject.Create(activityMark.Id);
  407. activityObject.Position = activityMark.Position;
  408. activityObject.VerticalSpeed = activityMark.VerticalSpeed;
  409. activityObject.Altitude = activityMark.Altitude;
  410. return activityObject;
  411. }
  412.  
  413. //获取物体默认所在层级
  414. private RoomLayerEnum GetDefaultLayer(ActivityMark activityMark)
  415. {
  416. if (activityMark.ActivityType == ActivityType.Player || activityMark.ActivityType == ActivityType.Enemy || activityMark.ActivityType == ActivityType.Treasure)
  417. {
  418. return RoomLayerEnum.YSortLayer;
  419. }
  420.  
  421. return RoomLayerEnum.NormalLayer;
  422. }
  423. /// <summary>
  424. /// 获取房间内的玩家生成标记
  425. /// </summary>
  426. public ActivityMark GetPlayerBirthMark()
  427. {
  428. if (WaveList.Count == 0)
  429. {
  430. return null;
  431. }
  432.  
  433. var activityMarks = WaveList[0];
  434. var activityMark = activityMarks.FirstOrDefault(mark => mark.MarkType == SpecialMarkType.BirthPoint);
  435. return activityMark;
  436. }
  437.  
  438. public void Destroy()
  439. {
  440. if (IsDestroyed)
  441. {
  442. return;
  443. }
  444.  
  445. IsDestroyed = true;
  446. if (_coroutineId >= 0)
  447. {
  448. World.Current.StopCoroutine(_coroutineId);
  449. }
  450.  
  451. WaveList.Clear();
  452. if (_readyList != null)
  453. {
  454. foreach (var preloadData in _readyList)
  455. {
  456. preloadData.ActivityObject.Destroy();
  457. }
  458.  
  459. _readyList.Clear();
  460. }
  461. }
  462.  
  463. //初始化物体属性
  464. private void InitAttr(ActivityObject activityObject, ActivityMark activityMark)
  465. {
  466. if (activityMark.Attr == null)
  467. {
  468. return;
  469. }
  470. if (activityMark.ActivityType == ActivityType.Weapon) //武器类型
  471. {
  472. var weapon = (Weapon)activityObject;
  473. if (activityMark.Attr.TryGetValue("CurrAmmon", out var currAmmon)) //当前弹夹弹药
  474. {
  475. weapon.SetCurrAmmo(int.Parse(currAmmon));
  476. }
  477. if (activityMark.Attr.TryGetValue("ResidueAmmo", out var residueAmmo)) //剩余弹药
  478. {
  479. weapon.SetResidueAmmo(int.Parse(residueAmmo));
  480. }
  481. }
  482. else if (activityMark.ActivityType == ActivityType.Enemy) //敌人类型
  483. {
  484. var role = (Role)activityObject;
  485. if (role.WeaponPack.Capacity > 0 && role is Enemy enemy && activityMark.Attr.TryGetValue("Weapon", out var weaponId)) //使用的武器
  486. {
  487. if (!string.IsNullOrEmpty(weaponId))
  488. {
  489. var weapon = ActivityObject.Create<Weapon>(weaponId);
  490. enemy.PickUpWeapon(weapon);
  491. if (activityMark.Attr.TryGetValue("CurrAmmon", out var currAmmon)) //当前弹夹弹药
  492. {
  493. weapon.SetCurrAmmo(int.Parse(currAmmon));
  494. }
  495. if (activityMark.Attr.TryGetValue("ResidueAmmo", out var residueAmmo)) //剩余弹药
  496. {
  497. weapon.SetResidueAmmo(int.Parse(residueAmmo));
  498. }
  499. }
  500. }
  501.  
  502. if (activityMark.DerivedAttr != null && activityMark.DerivedAttr.TryGetValue("Face", out var face)) //脸朝向, 应该只有 -1 和 1
  503. {
  504. var faceDir = int.Parse(face);
  505. role.Face = (FaceDirection)faceDir;
  506. }
  507. }
  508. }
  509. }