|
|
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();
|
|
|
}
|
|
|
}
|
|
|
} |