using FL.Battle; using FL.Data; using FL.FGUI; using FL.Map; using System.Collections.Generic; using System.Linq; using UnityEngine; using XGame; using XGame.Database; using XGame.Framework.Interfaces; using XGame.Framework.Map; using XGame.Framework.Nodes; using XGame.Framework.Time; namespace FL.Nodes.GameMain { public class MapComponent : NodeComponent, IUpdate { private int _chapterId; private EMapSchedule _schedule; private ITimer _monsterTimer; /// /// boss战斗倒计时 /// private ITimer _bossTimer; private PlayerEntity _player; /// /// 怪物坐标相对出生点的偏移值 /// 怪物最多13个,分两排排列,索引如下 /// 二排 9 5 1 2 6 10 /// 一排 11 7 3 0 4 8 12 /// 0的左边偏移值为负数 /// private Vector3 _monsterOffset = new Vector3(0.8f, 1.5f, 0); /// /// 空闲的怪物位置索引 /// private List _unusedIndexs; /// /// 怪物的实例对象 /// private Dictionary _monsterMap; /// /// 伙伴的实例对象 /// private Dictionary _partnerMap; private MapKey _currentMap; public override void OnEnable(object intent) { EventSingle.Instance.AddListener(EventDefine.GameMainMapRemoveEntity, OnRemoveEntity); EventSingle.Instance.AddListener(EventDefine.GameMainMapEndMask, OnMapEndMask); EventSingle.Instance.AddListener(EventDefine.PartnerDown, OnPartnerDown); EventSingle.Instance.AddListener(EventDefine.PartnerUp, OnPartnerUp); InitMonsters(); StartMap(PlayerData.Instance.chapterId); } public override void OnDisable() { EventSingle.Instance.RemoveListener(EventDefine.GameMainMapRemoveEntity, OnRemoveEntity); EventSingle.Instance.RemoveListener(EventDefine.GameMainMapEndMask, OnMapEndMask); EventSingle.Instance.RemoveListener(EventDefine.PartnerDown, OnPartnerDown); EventSingle.Instance.RemoveListener(EventDefine.PartnerUp, OnPartnerUp); _player = null; _partnerMap?.Clear(); _monsterTimer?.Cancel(); _monsterTimer = null; _bossTimer?.Cancel(); _bossTimer = null; _monsterMap?.Clear(); _unusedIndexs?.Clear(); Context.Map.Close(_currentMap); _currentMap = null; } void IUpdate.Update(int millisecond) { if (_player == null) return; } private void InitMonsters() { if (_unusedIndexs == null) _unusedIndexs = new List(); else _unusedIndexs.Clear(); for (var i = 0; i < 13; i++) { _unusedIndexs.Add(i); } } private void StartMap(int chapterId) { _chapterId = chapterId; _schedule = EMapSchedule.LoadingMap; var chapter = ChapterTableRepo.Get(_chapterId); var map = MapTableRepo.Get(chapter.Map); var mapKey = MapKeys.NameToKey(map.AssetName); if (mapKey == _currentMap) { // 是同一个地图 StartChapter(true, false); } else { // 关闭当前地图 Context.Map.Close(_currentMap); _currentMap = mapKey; // 加载新地图 var mapAsync = Context.Map.RunAsync(mapKey); mapAsync.On(_ => { StartChapter(true, true); }); } } private void StartChapter(bool isChapterChanged, bool isMapChanged) { _schedule = EMapSchedule.Monster1; var chapter = ChapterTableRepo.Get(_chapterId); var map = MapTableRepo.Get(chapter.Map); var dto = new LoadEntitiesDto(); dto.chapterId = _chapterId; dto.isChapterChanged = isChapterChanged; dto.isBossPart = chapter.Part_type == 1; dto.isPlayerMove = true; //战斗位置 dto.battlePosition = GetBattlePosition(map, chapter.Part);// map.BattlePositions[chapter.Part - 1].ToVector3(); var isGenPlayer = _player == null; if (isGenPlayer) { _player = GenPlayer(map.PlayerBirth.ToVector3()); //玩家 dto.player = _player; //伙伴 var partners = GenPartners(_player.BirthPosition); AddPartners(partners); dto.partners = partners; } else if (isMapChanged) { //玩家 dto.player = _player; //伙伴 dto.partners = _partnerMap.Values.ToArray(); } if (isChapterChanged || dto.isBossPart) { // 重置玩家血量 _player.Attr.Dynamic.Clear(); _player.Attr.ResetHp(); } if (isChapterChanged) { // 随从可能有替换过,重置随从的出生点 var birthPosition = _player.BirthPosition; foreach (var partner in _partnerMap.Values) { partner.BirthPosition = birthPosition + PartnersData.Instance.GetPartnerOffset(partner.Attr.UID); } } //怪物数据 var monsters = GenMonsters(); AddMonsters(monsters); dto.monsters = monsters; dto.monsterMoveDistance = map.MonsterBirth.Y - map.BattleFirst.Y;// map.MonsterPositions[chapter.Part - 1].ToVector3().y - dto.battlePosition.y; //定时器 if (!dto.isBossPart) { // 普通节点,增加定时器 dto.monsterMoveDelay = 0; _monsterTimer = Context.Time.AddDelayLooperTimer(chapter.Interval * 6, chapter.Interval * 6, OnLoopGenMonsters); } else { // boss关卡,直接到最后 dto.monsterMoveDelay = 1000; _schedule = EMapSchedule.Monster5; Context.UI.OpenAsync(UIKeys.MainBossLaiXi); Context.Time.AddDelayTimer(1000, () => { //1秒后自动关闭 Context.UI.Close(UIKeys.MainBossLaiXi); if (chapter.Time > 0) {// boss战斗倒计时 _bossTimer = Context.Time.AddDelayTimer(chapter.Time, CombatFailed); EventSingle.Instance.Notify(EventDefine.GameMainMapBossStart, chapter.Id); } }); } EventSingle.Instance.Notify(EventDefine.GameMainMapLoadEntities, dto); } private void OnLoopGenMonsters(int times) { _schedule += 1; if (_schedule == EMapSchedule.Monster5) { _monsterTimer.Cancel(); _monsterTimer = null; } var chapter = ChapterTableRepo.Get(_chapterId); var map = MapTableRepo.Get(chapter.Map); var dto = new LoadEntitiesDto(); dto.chapterId = _chapterId; //战斗位置 dto.battlePosition = GetBattlePosition(map, chapter.Part);// map.BattlePositions[chapter.Part - 1].ToVector3(); //怪物数据 var monsters = GenMonsters(); AddMonsters(monsters); dto.monsters = monsters; dto.monsterMoveDistance = map.MonsterBirth.Y - map.BattleFirst.Y;// map.MonsterPositions[chapter.Part - 1].ToVector3().y - dto.battlePosition.y; EventSingle.Instance.Notify(EventDefine.GameMainMapLoadEntities, dto); } private PlayerEntity GenPlayer(Vector3 birth) { var playerData = PlayerData.Instance; var player = new PlayerEntity() { BirthPosition = birth//玩家出生点 }; var entityAttr = new EntityAttributes(0, playerData.UID) { Name = playerData.Name, Radius = 1, AttackCD = 2000, }; entityAttr.CopyFrom(playerData.Attr); player.Init(UIDDefine.New(), entityAttr, playerData.skillIds); return player; } private PartnerEntity[] GenPartners(Vector3 targetPosition) { var goneUpMap = PartnersData.Instance.GoneUpMap; var count = goneUpMap.Count; var partners = new PartnerEntity[count]; var index = 0; foreach (var partnerUID in goneUpMap.Keys) { partners[index++] = GenPartner(targetPosition, partnerUID); } return partners; } private PartnerEntity GenPartner(Vector3 targetPosition, long partnerId) { var partner = PartnersData.Instance.PartnersMap[partnerId]; var entity = new PartnerEntity() { BirthPosition = targetPosition + PartnersData.Instance.GetPartnerOffset(partner.UID), EpigraphId = 20300, }; var entityAttr = new EntityAttributes(partner.TableId, partner.UID) { Name = partner.Name, Radius = partner.Radius, AttackCD = 6000, }; entityAttr.CopyFrom(partner.Attr); var table = PartnerTableRepo.Get(partner.TableId); entity.Init(UIDDefine.New(), entityAttr, new int[] { partner.SkillId }); return entity; } private void AddPartners(PartnerEntity[] partners) { if (partners == null || partners.Length == 0) return; if (_partnerMap == null) { _partnerMap = new Dictionary(); } foreach (var partner in partners) { _partnerMap.Add(partner.EntityId, partner); } } /// /// 获取怪物的出生坐标和索引 /// /// /// /// private Vector3 GetMonsterBirth(Vector3 position, out int positionIdx) { if (_unusedIndexs.Count > 0) { positionIdx = _unusedIndexs[0]; _unusedIndexs.RemoveAt(0); } else { positionIdx = 0; } if (positionIdx == 0) { return position; } var offset = Vector3.zero; var xMultiple = (positionIdx + 1) / 2; offset.x = _monsterOffset.x * xMultiple; if (positionIdx % 2 != 0) { // 索引为奇数的在左边 offset.x = -offset.x; } if (xMultiple % 2 != 0) { // 倍数为奇数的在上面 offset.y = _monsterOffset.y; } var target = position + offset; // 随机偏移xy(-0.2, 0.2) target.x += Random.Range(-0.25f, 0.25f); target.y += Random.Range(-0.25f, 0.25f); return target; } private void PushMonstPositionIdx(int positionIdx) { if (_unusedIndexs.Contains(positionIdx)) return; // 避免重复记录 for (var i = 0; i < _unusedIndexs.Count; i++) { if (positionIdx < _unusedIndexs[i] && (i == 0 || positionIdx > _unusedIndexs[i - 1])) { // 小于当前索引的值 且 大于(i - 1 )的值 _unusedIndexs.Insert(i, positionIdx); return; } } _unusedIndexs.Add(positionIdx); } private MonsterEntity[] GenMonsters() { var chapter = ChapterTableRepo.Get(_chapterId); var map = MapTableRepo.Get(chapter.Map); Vector3 birthPosition = GetMonsterBirth(map, chapter.Part);// map.MonsterPositions[chapter.Part - 1].ToVector3(); int[] monsterRefresh = null; switch (_schedule) { case EMapSchedule.Monster1: monsterRefresh = chapter.Monster_refresh1; break; case EMapSchedule.Monster2: monsterRefresh = chapter.Monster_refresh2; break; case EMapSchedule.Monster3: monsterRefresh = chapter.Monster_refresh3; break; case EMapSchedule.Monster4: monsterRefresh = chapter.Monster_refresh4; break; case EMapSchedule.Monster5: monsterRefresh = chapter.Monster_refresh5; break; default: break; } var monsterCount = (monsterRefresh != null && monsterRefresh.Length > 0) ? monsterRefresh[1] : 0; if (monsterCount > 0) { // 数量0-3 var monsters = new MonsterEntity[monsterCount]; for (var i = 0; i < monsterCount; i++) { var position = GetMonsterBirth(birthPosition, out var positionIdx); var monsterTab = MonsterTableRepo.Get(monsterRefresh[0]); var entityAttr = new EntityAttributes(monsterTab.Id, UIDDefine.New()) { Name = monsterTab.Name, Radius = monsterTab.ModelSize * 0.5f, AttackCD = 3000, }; entityAttr.Static.Hp = monsterTab.Hp; entityAttr.Static.HpLimit = monsterTab.Hp; entityAttr.Static.MoveSpeed = Mathf.RoundToInt(monsterTab.Speed); entityAttr.Static.Attack = monsterTab.Atk; entityAttr.CurrentHp = monsterTab.Hp; var entity = new MonsterEntity(); entity.Init(UIDDefine.New(), entityAttr, monsterTab.Skills); entity.BirthPosition = position; entity.PositionIdx = positionIdx; monsters[i] = entity; } return monsters; } return null; } private void AddMonsters(MonsterEntity[] monsters) { if (monsters == null || monsters.Length == 0) return; if (_monsterMap == null) { _monsterMap = new Dictionary(); } foreach (var monsterInfo in monsters) { _monsterMap.Add(monsterInfo.EntityId, monsterInfo); } } #region 事件监听 private void OnRemoveEntity(int eventId, object args) { var entityId = (long)args; if (_monsterMap.TryGetValue(entityId, out var entity)) { _monsterMap.Remove(entityId); PushMonstPositionIdx(entity.PositionIdx); CheckMonsterAllDead(); return; } if (_partnerMap.TryGetValue(entityId, out var partner)) { _partnerMap.Remove(entityId); return; } if (entityId == _player.EntityId) { //TODO 失败结算 CombatFailed(); } } private void OnPartnerDown(int eventId, object args) { var partnerUID = (long)args; var entityId = GetPartnerEntityIdByUID(partnerUID); if (entityId == 0) return; EventSingle.Instance.Notify(EventDefine.GameMainMapRemoveEntity, entityId); } private void OnPartnerUp(int eventId, object args) { var partnerUID = (long)args; var entityId = GetPartnerEntityIdByUID(partnerUID); if (entityId != 0) return; // 已经有实例对象了 var chapter = ChapterTableRepo.Get(_chapterId); var map = MapTableRepo.Get(chapter.Map); var dto = new LoadEntitiesDto(); dto.chapterId = _chapterId; //战斗位置 dto.battlePosition = GetBattlePosition(map, chapter.Part);// map.BattlePositions[chapter.Part - 1].ToVector3(); var partner = GenPartner(dto.battlePosition, partnerUID); var partners = new PartnerEntity[] { partner }; AddPartners(partners); dto.partners = partners; EventSingle.Instance.Notify(EventDefine.GameMainMapLoadEntities, dto); } //private void OnExchangePartner(int eventId, object args) //{ // var addPartners = (List)args; // var activePartnerIds = PartnersData.Instance.ActiveUIDs; // var count = addPartners.Count; // // 从后往前移除 // for (var i = 0; i < count; i++) // { // var partnerId = activePartnerIds[activePartnerIds.Count - 1]; // activePartnerIds.RemoveAt(activePartnerIds.Count - 1); // var EntityId = GetPartnerUIDByTableId(partnerId); // if (EntityId == 0) // continue; // EventSingle.Instance.Notify(EventDefine.GameMainMapRemoveEntity, EntityId); // } // activePartnerIds.AddRange(addPartners); // var chapter = ChapterTableRepo.Get(_chapterId); // var map = MapTableRepo.Get(chapter.Map); // var dto = new LoadEntitiesDto(); // dto.chapterId = _chapterId; // //战斗位置 // dto.battlePosition = map.BattlePositions[chapter.Part - 1].ToVector3(); // var partners = GenPartners(dto.battlePosition, addPartners); // AddPartners(partners); // dto.partners = partners; // EventSingle.Instance.Notify(EventDefine.GameMainMapLoadEntities, dto); //} private void OnMapEndMask(int eventId, object args) { var isSuccess = (bool)args; var chapter = ChapterTableRepo.Get(_chapterId); int chapterId; if (isSuccess) { var nextChapter = ChapterTableRepo.Next(_chapterId); //没找到新关卡,重新开始 if (nextChapter == null || nextChapter.Chapter != chapter.Chapter) { // 没有新关卡 || 章节id变化 //TODO 章节切换 } chapterId = nextChapter?.Id ?? PlayerData.Instance.chapterId; } //else if (chapter.Part_type == 1) //{ // boss节点失败,进入本关卡小怪节点循环 // TODO //} else { // 普通节点失败,重置到本关卡第一个节点 chapterId = _chapterId / 10 * 10 + 1; } StartMap(chapterId); } #endregion private void CheckMonsterAllDead() { if (_monsterMap.Count > 0) return; // 怪物全部死亡 var chapter = ChapterTableRepo.Get(_chapterId); if (chapter.Part_type == 1) { //boss关卡 //TODO 结算 _bossTimer?.Cancel(); _bossTimer = null; Context.UI.OpenAsync(UIKeys.MainBattleOverVictory); Context.Time.AddDelayTimer(2000, () => { //2秒后自动关闭 Context.UI.Close(UIKeys.MainBattleOverVictory); EventSingle.Instance.Notify(EventDefine.GameMainMapStartMask, true); }); } else if (_schedule == EMapSchedule.Monster5) { _chapterId++; StartChapter(false, false); } } /// /// 战斗失败 /// private void CombatFailed() { // 清空怪物数据 foreach(var item in _monsterMap) { PushMonstPositionIdx(item.Value.PositionIdx); } _monsterMap.Clear(); Context.UI.OpenAsync(UIKeys.MainBattleOverFail); EventSingle.Instance.Notify(EventDefine.GameMainMapStartMask, false); } private long GetPartnerEntityIdByUID(long uid) { foreach (var item in _partnerMap) { if (item.Value.Attr.UID == uid) return item.Key; } return 0; } private Vector3 GetBattlePosition(MapTable map, int mapPart) { return map.BattleFirst.ToVector3() + map.PartMove.ToVector3() * (mapPart - 1); } private Vector3 GetMonsterBirth(MapTable map, int mapPart) { return map.MonsterBirth.ToVector3() + map.PartMove.ToVector3() * (mapPart - 1); } } }