|  |  | using System.Collections.Generic;
 | 
						
						
						
							|  |  | using Game;
 | 
						
						
						
							|  |  | using UnityEngine;
 | 
						
						
						
							|  |  | using Articy.Touhou.Features;
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  | public class LevelPoolItem : ObjectPoolItemBase
 | 
						
						
						
							|  |  | {
 | 
						
						
						
							|  |  |     public string CfgId;
 | 
						
						
						
							|  |  |     public LevelFeature Cfg;
 | 
						
						
						
							|  |  |     public LevelNodeMonsterWave CurWave; //当前波次配置
 | 
						
						
						
							|  |  |     public BehaviorTreePoolItem BehaviorTree;//行为树
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     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 textureSizeX = mainTexture.width / 64f;
 | 
						
						
						
							|  |  |             var textureSizeY = mainTexture.height / 64f;
 | 
						
						
						
							|  |  |             _wallMaterialList.Add(material);
 | 
						
						
						
							|  |  |             if (item.transform.localScale.z > 1f)
 | 
						
						
						
							|  |  |             {
 | 
						
						
						
							|  |  |                 //竖向墙
 | 
						
						
						
							|  |  |                 material.mainTextureScale = new Vector2(levelRect.x / textureSizeX, 20 / textureSizeY) * 2;
 | 
						
						
						
							|  |  |             }
 | 
						
						
						
							|  |  |             else
 | 
						
						
						
							|  |  |             {
 | 
						
						
						
							|  |  |                 //横向墙
 | 
						
						
						
							|  |  |                 material.mainTextureScale = new Vector2(levelRect.y / textureSizeX, 20 / textureSizeY) * 2;
 | 
						
						
						
							|  |  |             }
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  |         
 | 
						
						
						
							|  |  |         //导演AI
 | 
						
						
						
							|  |  |         BehaviorTree = BehaviorTreePoolManager.Instance.CreateAILevel(Cfg.AIRes);
 | 
						
						
						
							|  |  |         var levelInfo = _gameObject.AddComponent<LevelInfo>();
 | 
						
						
						
							|  |  |         levelInfo.Tree = BehaviorTree.AIObject.Tree();
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |     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();
 | 
						
						
						
							|  |  |                 }
 | 
						
						
						
							|  |  |             });
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  |         
 | 
						
						
						
							|  |  |         ((IAIDirector)BehaviorTree.AIObject).Reset();
 | 
						
						
						
							|  |  | 
 | 
						
						
						
							|  |  |         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 itemLevelNodeMonsterWave)) continue;
 | 
						
						
						
							|  |  |                 if (itemLevelNodeMonsterWave.GetWaveIndex() != _waveNow) continue;
 | 
						
						
						
							|  |  |                 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();
 | 
						
						
						
							|  |  |         }
 | 
						
						
						
							|  |  |     }
 | 
						
						
						
							|  |  | } |