|  |  |  |  | using System.Collections.Generic; | 
					
						
							|  |  |  |  | using Game; | 
					
						
							|  |  |  |  | using UnityEngine; | 
					
						
							|  |  |  |  | using Articy.Touhou.Features; | 
					
						
							|  |  |  |  | using Ludiq; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | public class LevelPoolItem : ObjectPoolItemBase | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     public string CfgId; | 
					
						
							|  |  |  |  |     public LevelFeature Cfg; | 
					
						
							|  |  |  |  |     public LevelNodeMonsterWave CurWave; //当前波次配置 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     private GameObject _gameObject; | 
					
						
							|  |  |  |  |     private Vector3 _playerBorn = GameConst.NoneDir; //玩家出生点 | 
					
						
							|  |  |  |  |     private int _waveMax = 0; //最大波数 | 
					
						
							|  |  |  |  |     private int _waveNow = 0; //当前波数 | 
					
						
							|  |  |  |  |     private int _monsterCount = 0; //场景内怪物数 | 
					
						
							|  |  |  |  |     private readonly List<LevelNode> _levelData = new List<LevelNode>(); | 
					
						
							|  |  |  |  |     private readonly List<LevelNodeDoor> _doorList = new List<LevelNodeDoor>(); | 
					
						
							|  |  |  |  |     private readonly List<LevelNodePlayerBorn> _playerBornList = new List<LevelNodePlayerBorn>(); | 
					
						
							|  |  |  |  |     private readonly List<int> _interactList = new List<int>(); //通关后打开的交互物 | 
					
						
							|  |  |  |  |     private readonly List<Material> _wallMaterialList = new List<Material>(); | 
					
						
							|  |  |  |  |     private static readonly int WorldPos = Shader.PropertyToID("_WorldPos"); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     protected override void OnCreate() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         base.OnCreate(); | 
					
						
							|  |  |  |  |         _gameObject.SetActive(true); | 
					
						
							|  |  |  |  |         EventManager.Instance.AddEvent<PEntityAlive>(EEvent.EntityAlive, OnEntityAlive); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     protected override void OnDestroy() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         EventManager.Instance.RemoveEvent<PEntityAlive>(EEvent.EntityAlive, OnEntityAlive); | 
					
						
							|  |  |  |  |         base.OnDestroy(); | 
					
						
							|  |  |  |  |         DestroyLevel(); | 
					
						
							|  |  |  |  |         _gameObject.SetActive(false); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     protected override void OnCreateBind() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         var master = Util.GetMaster(); | 
					
						
							|  |  |  |  |         BindData(master.view.PosView, ((pre, now) => | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             foreach (var item in _wallMaterialList) | 
					
						
							|  |  |  |  |             { | 
					
						
							|  |  |  |  |                 item.SetVector(WorldPos, now); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         })); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     public void Init() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         //关卡配置解析 | 
					
						
							|  |  |  |  |         var prefabPath = Cfg.Prefab; | 
					
						
							|  |  |  |  |         //关卡go创建 | 
					
						
							|  |  |  |  |         _gameObject = LevelPoolManager.Instance.CreateLevelGo(prefabPath); | 
					
						
							|  |  |  |  |         //位置分布 | 
					
						
							|  |  |  |  |         var nodes = _gameObject.GetComponentsInChildren<LevelNode>(); | 
					
						
							|  |  |  |  |         foreach (var item in nodes) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             item.SetPos(item.transform.position); | 
					
						
							|  |  |  |  |             item.OnInit(); | 
					
						
							|  |  |  |  |             switch (item) | 
					
						
							|  |  |  |  |             { | 
					
						
							|  |  |  |  |                 case LevelNodePlayerBorn born: | 
					
						
							|  |  |  |  |                     _playerBornList.Add(born); | 
					
						
							|  |  |  |  |                     continue; | 
					
						
							|  |  |  |  |                 case LevelNodeMonster itemLevelNodeMonster: | 
					
						
							|  |  |  |  |                     var monsterId = Cfg.MonsterList[itemLevelNodeMonster.monsterIndex].TechnicalName; | 
					
						
							|  |  |  |  |                     itemLevelNodeMonster.SetCfgId(monsterId); | 
					
						
							|  |  |  |  |                     continue; | 
					
						
							|  |  |  |  |                 case LevelNodeMonsterWave itemLevelNodeMonsterWave: | 
					
						
							|  |  |  |  |                     if (itemLevelNodeMonsterWave.transform.childCount == 0) | 
					
						
							|  |  |  |  |                         continue; | 
					
						
							|  |  |  |  |                     itemLevelNodeMonsterWave.SetWaveIndex(_waveMax); | 
					
						
							|  |  |  |  |                     _waveMax++; | 
					
						
							|  |  |  |  |                     break; | 
					
						
							|  |  |  |  |                 case LevelNodeDoor door: | 
					
						
							|  |  |  |  |                     door.SetCfgId(Cfg.Door.TechnicalName); | 
					
						
							|  |  |  |  |                     door.SetTargetLevel(Cfg); | 
					
						
							|  |  |  |  |                     _doorList.Add(door); | 
					
						
							|  |  |  |  |                     break; | 
					
						
							|  |  |  |  |                 case LevelNodeNpc npc: | 
					
						
							|  |  |  |  |                     npc.SetCfgId(npc.npcId); | 
					
						
							|  |  |  |  |                     npc.SetTargetId(npc.dialogId); | 
					
						
							|  |  |  |  |                     break; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             _levelData.Add(item); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         //开启阴影 | 
					
						
							|  |  |  |  |         var sprites = _gameObject.GetComponentsInChildren<SpriteRenderer>(); | 
					
						
							|  |  |  |  |         foreach (var item in sprites) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             item.receiveShadows = false; | 
					
						
							|  |  |  |  |             item.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         //墙壁 | 
					
						
							|  |  |  |  |         var levelRect = new Vector2(Cfg.LevelSizeX, Cfg.LevelSizeY) * 12.81f; | 
					
						
							|  |  |  |  |         var walls = _gameObject.GetComponentsInChildren<LevelMarkAirWall>(); | 
					
						
							|  |  |  |  |         foreach (var item in walls) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             if (!item.TryGetComponent<MeshRenderer>(out var meshRenderer)) continue; | 
					
						
							|  |  |  |  |             var material = meshRenderer.material; | 
					
						
							|  |  |  |  |             var mainTexture = (Texture2D)material.mainTexture; | 
					
						
							|  |  |  |  |             var textureSize = mainTexture.Size() / 64f; | 
					
						
							|  |  |  |  |             _wallMaterialList.Add(material); | 
					
						
							|  |  |  |  |             if (item.transform.localScale.z > 1f) | 
					
						
							|  |  |  |  |             { | 
					
						
							|  |  |  |  |                 //竖向墙 | 
					
						
							|  |  |  |  |                 material.mainTextureScale = new Vector2(levelRect.x / textureSize.x, 20 / textureSize.y) * 2; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             else | 
					
						
							|  |  |  |  |             { | 
					
						
							|  |  |  |  |                 //横向墙 | 
					
						
							|  |  |  |  |                 material.mainTextureScale = new Vector2(levelRect.y / textureSize.x, 20 / textureSize.y) * 2; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     public void SetPlayerBorn(string preLevelId) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         //出生点选取规则:优先选择关卡连接关系对应,否则从playerBorn中随机 | 
					
						
							|  |  |  |  |         _playerBorn = GameConst.NoneDir; | 
					
						
							|  |  |  |  |         if (!string.IsNullOrEmpty(preLevelId)) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             foreach (var item in _doorList) | 
					
						
							|  |  |  |  |             { | 
					
						
							|  |  |  |  |                 if (item.IsFromPreLevel(preLevelId)) | 
					
						
							|  |  |  |  |                 { | 
					
						
							|  |  |  |  |                     _playerBorn = item.GetPos(); | 
					
						
							|  |  |  |  |                     return; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (_playerBornList.Count > 0) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             _playerBorn = GameRandom.Pick(_playerBornList).GetPos(); | 
					
						
							|  |  |  |  |             return; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         Util.Print("关卡配置错误,没有出生点"); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     public void CreateLevel() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         Util.GetMaster().SetFixedPos(_playerBorn); | 
					
						
							|  |  |  |  |         foreach (var item in _levelData) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             if (item is LevelNodeMonsterWave) | 
					
						
							|  |  |  |  |             { | 
					
						
							|  |  |  |  |                 continue; //进入关卡时不刷怪 | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             Util.CreateEntity(item.GetCfgId(), (entity) => | 
					
						
							|  |  |  |  |             { | 
					
						
							|  |  |  |  |                 entity.SetPos(item.GetPos()); | 
					
						
							|  |  |  |  |                 if (item is LevelNodeDoor) | 
					
						
							|  |  |  |  |                 { | 
					
						
							|  |  |  |  |                     entity.interact.TargetId = item.GetTargetId(); | 
					
						
							|  |  |  |  |                     entity.interact.IsActive.Value = _waveMax == 0; | 
					
						
							|  |  |  |  |                     _interactList.Add(entity.ID()); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 if (item is LevelNodeNpc) | 
					
						
							|  |  |  |  |                 { | 
					
						
							|  |  |  |  |                     entity.interact.TargetId = item.GetTargetId(); | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             }); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         NextWave(); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     private void NextWave() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         _monsterCount = 0; | 
					
						
							|  |  |  |  |         var isOk = false; | 
					
						
							|  |  |  |  |         if (_waveNow > _waveMax) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             Util.Print("通关"); | 
					
						
							|  |  |  |  |             //通关 | 
					
						
							|  |  |  |  |             foreach (var interact in _interactList) | 
					
						
							|  |  |  |  |             { | 
					
						
							|  |  |  |  |                 var entity = Util.GetEntity(interact); | 
					
						
							|  |  |  |  |                 if (entity != null) | 
					
						
							|  |  |  |  |                 { | 
					
						
							|  |  |  |  |                     entity.interact.IsActive.Value = true; | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             isOk = true; | 
					
						
							|  |  |  |  |             //TODO | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         else | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             foreach (var item in _levelData) | 
					
						
							|  |  |  |  |             { | 
					
						
							|  |  |  |  |                 if (item is LevelNodeMonsterWave) | 
					
						
							|  |  |  |  |                 { | 
					
						
							|  |  |  |  |                     var itemLevelNodeMonsterWave = item as LevelNodeMonsterWave; | 
					
						
							|  |  |  |  |                     if (itemLevelNodeMonsterWave.GetWaveIndex() == _waveNow) | 
					
						
							|  |  |  |  |                     { | 
					
						
							|  |  |  |  |                         foreach (var monster in itemLevelNodeMonsterWave.GetMonsters()) | 
					
						
							|  |  |  |  |                         { | 
					
						
							|  |  |  |  |                             Util.CreateEntity(monster.GetCfgId(), (entity) => { entity.SetPos(monster.GetPos()); }); | 
					
						
							|  |  |  |  |                         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                         isOk = true; | 
					
						
							|  |  |  |  |                         CurWave = itemLevelNodeMonsterWave; | 
					
						
							|  |  |  |  |                         break; | 
					
						
							|  |  |  |  |                     } | 
					
						
							|  |  |  |  |                 } | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             if (isOk) | 
					
						
							|  |  |  |  |             { | 
					
						
							|  |  |  |  |                 Util.Print("创建怪物实体 波数:", _waveNow); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         _waveNow++; | 
					
						
							|  |  |  |  |         if (!isOk) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             NextWave(); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     private void DestroyLevel() | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         //TODO 销毁实体、特效等 | 
					
						
							|  |  |  |  |         var entities = Util.GetGroup(GameMatcher.ID); | 
					
						
							|  |  |  |  |         foreach (var item in entities) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             if (item.IsMaster() || item.IsMasterSoul()) | 
					
						
							|  |  |  |  |             { | 
					
						
							|  |  |  |  |                 continue; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             item.OnDie(); | 
					
						
							|  |  |  |  |             item.iD.Data.IsDestroy = true; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         //销毁残影和尸体 | 
					
						
							|  |  |  |  |         Util.DestroyCastShadowAll(); | 
					
						
							|  |  |  |  |         _waveNow = 0; | 
					
						
							|  |  |  |  |         CurWave = null; | 
					
						
							|  |  |  |  |         _interactList.Clear(); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     private void OnEntityAlive(PEntityAlive param) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         var entity = param.Entity; | 
					
						
							|  |  |  |  |         if (entity == Util.GetMasterID()) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             return; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         _monsterCount += (param.IsAlive ? 1 : -1); | 
					
						
							|  |  |  |  |         if (_monsterCount == 0) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             NextWave(); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | } |