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