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