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