using FairyGUI;
using FL.Battle;
using FL.Map.UI;
using FL.Nodes.GameMain;
using System.Collections.Generic;
using UnityEngine;
using XGame;
using XGame.Database;
using XGame.Framework;
using XGame.Framework.Asyncs;
using XGame.Framework.Components;
using XGame.Framework.Interfaces;
using XGame.Framework.Map;
using XGame.Framework.Time;
namespace FL.Map.TestMainMap
{
public interface IMapUIContext
{
IMapAssetModule Asset { get; }
ITimeModule Time { get; }
TestMainMapVM VM { get; }
}
///
/// 地图用UI
///
public class MapUIComponent : Component, ILateUpdate
{
private MainMapUIView _uiView;
private IAsync _uiViewAsync;
///
/// 玩家、怪物血条
///
private Dictionary _entityViewsMap = new();
///
/// 飘血计时
/// 同一个Entity的飘血需要有200毫秒间隔
///
private Dictionary _hpAddLastTimeMap = new Dictionary();
private HashSet _hpAddTimers = new();
///
/// TODO
///
private Camera UICamera => StageCamera.main;
private int _chapterId;
private bool _isMasking;
protected override void OnEnable(object intent)
{
EventSingle.Instance.AddListener(EventDefine.GameMainMapRemoveEntity, OnRemoveEntity);
EventSingle.Instance.AddListener(EventDefine.GameMainMapStartMask, OnStartMask);
EventSingle.Instance.AddListener(EventDefine.GameMainMapEndMask, OnEndMask);
EventSingle.Instance.AddListener(EventDefine.GameMainMapHpAdd, OnHpAdd);
LoadUIView();
}
protected override void OnDisable()
{
EventSingle.Instance.RemoveListener(EventDefine.GameMainMapRemoveEntity, OnRemoveEntity);
EventSingle.Instance.RemoveListener(EventDefine.GameMainMapStartMask, OnStartMask);
EventSingle.Instance.RemoveListener(EventDefine.GameMainMapEndMask, OnEndMask);
EventSingle.Instance.RemoveListener(EventDefine.GameMainMapHpAdd, OnHpAdd);
if (_uiView != null)
{
Context.Asset.Recycle(_uiView);
_uiView = null;
}
if (_uiViewAsync != null)
{
_uiViewAsync.RemoveAll();
_uiViewAsync = null;
}
ClearEntities(true);
_chapterId = 0;
_isMasking = false;
}
protected override void OnDispose()
{
}
void ILateUpdate.LateUpdate(int millisecond)
{
if (_entityViewsMap.Count > 0)
{
var cameraMoving = Context.VM.Camera.IsMoving;
foreach (var view in _entityViewsMap.Values)
{
if ((cameraMoving || view.Master.IsMoving) && view.IsMoveable)
{
view.LocalPosition = WorldToLocal(view.Master.UIPoint.position, _uiView.PlayerRoot);
}
view.RefreshBuffs();
}
}
}
///
/// 世界坐标转指定UI节点的相对坐标
///
///
///
///
private Vector2 WorldToLocal(Vector3 position, Transform parent)
{
var screenPoint = Context.VM.Camera.WorldToScreenPoint(position);
RectTransformUtility.ScreenPointToLocalPointInRectangle(parent as RectTransform, screenPoint, UICamera, out var localPoint);
return localPoint;
}
public void AddEntity(ITarget master)
{
if (_uiView == null)
{
if (_uiViewAsync != null)
{
_uiViewAsync.On(_ =>
{
LoadEntityView(master);
});
}
else
{
Log.Error($"MainMapUI不能为空.");
}
}
else
{
LoadEntityView(master);
}
}
public void AddBoss(ITarget master, int chapterId)
{
Assert.IsNotNull(_uiView, $"MainMapUI不能为空.");
LoadEntityView(master, chapterId);
}
public void RefreshEntity(long entityId)
{
if (_entityViewsMap.TryGetValue(entityId, out var view))
{
view.RefreshHp();
}
}
private void LoadEntityView(ITarget master, int chapterId = 0)
{
if (master.Entity.EntityType == EEntityType.Monster)
{
var table = MonsterTableRepo.Get(master.Entity.TableId);
if (table.Type == 2)
{
var viewAsync = Context.Asset.LoadEntity(AddressableDefine.bossbattleinfo, _uiView.BossRoot);
viewAsync.On(_ =>
{
var view = viewAsync.Result;
if (view == null)
return;
OnLoaded(master, view);
view.IsMoveable = false;
view.LocalPosition = Vector3.zero;
view.RefreshTimeLimit(chapterId);
});
}
else
{
var viewAsync = Context.Asset.LoadEntity(AddressableDefine.monsterbattleinfo, _uiView.MonsterRoot);
viewAsync.On(_ =>
{
var view = viewAsync.Result;
if (view == null)
return;
OnLoaded(master, view);
});
}
}
else
{
var viewAsync = Context.Asset.LoadEntity(AddressableDefine.playerbattleinfo, _uiView.PlayerRoot);
viewAsync.On(_ =>
{
var view = viewAsync.Result;
if (view == null)
return;
OnLoaded(master, view);
});
}
}
void OnLoaded(ITarget master, IEntityBattleInfoView view)
{
if (master.IsDead)
{
Log.Debug($"EntityBattleInfoView 加载完成,Entity已经死亡. Id:{master.Entity.EntityId}");
Context.Asset.Recycle(view);
return;
}
view.Master = master;
view.IsMoveable = true;
view.LocalPosition = WorldToLocal(master.UIPoint.position, _uiView.PlayerRoot);
_entityViewsMap.Add(view.Master.Entity.EntityId, view);
}
private void OnRemoveEntity(int eventId, object args)
{
var entityId = (long)args;
if (_entityViewsMap.TryGetValue(entityId, out var view))
{
if (view.Master.Entity.EntityType == EEntityType.Player)
{ // 玩家的血条不移除
return;
}
_entityViewsMap.Remove(entityId);
Context.Asset.Recycle(view);
}
_hpAddLastTimeMap.Remove(entityId);
}
private void OnStartMask(int eventId, object args)
{
var sign = (EMapCombatSign)args; //0表示战斗胜利,1表示普通战斗失败,2表示boss战斗失败
if ( sign != EMapCombatSign.Success)
{ // 玩家死亡,失败,移除所有怪物的血条
ClearEntities(false);
if (sign is EMapCombatSign.FailedBoss)
{
_uiView?.SetBossFailed(true);
}
}
_isMasking = true;
}
private void OnEndMask(int eventId, object args)
{
//var sign = (EMapCombatSign)args;
_isMasking = false;
}
private void OnHpAdd(int eventId, object args)
{
PlayHpAdd((HpAddDto)args);
}
private void ClearEntities(bool includePlayer)
{
IEntityBattleInfoView player = null;
foreach (var entity in _entityViewsMap.Values)
{
if (!includePlayer && entity.Master.Entity.EntityType == EEntityType.Player)
{
player = entity;
continue;
}
Context.Asset.Recycle(entity);
}
_entityViewsMap.Clear();
_hpAddLastTimeMap.Clear();
foreach(var timer in _hpAddTimers)
{
timer.Cancel();
}
_hpAddTimers.Clear();
if (player != null)
{
_entityViewsMap.Add(player.Master.Entity.EntityId, player);
}
}
private void PlayHpAdd(HpAddDto dto)
{
if (_uiView == null || _isMasking)
return;
RefreshEntity(dto.entityId);
SaveHpAddTime(dto.entityId, out var delay);
if (delay > 0)
{
ITimer timer = null;
timer = Context.Time.AddDelayTimer(delay, () =>
{
_hpAddTimers.Remove(timer);
LoadHpAddView(dto);
});
_hpAddTimers.Add(timer);
}
else
{
LoadHpAddView(dto);
}
}
private void LoadHpAddView(HpAddDto dto)
{
var viewAsync = Context.Asset.LoadEntity(AddressableDefine.uihpadd, _uiView.CombatValRoot);
viewAsync.On(_ =>
{
var hpAddView = viewAsync.Result;
if (hpAddView == null)
return;
var localPoint = WorldToLocal(dto.position, _uiView.CombatValRoot);
//var screenPoint = Context.VM.Camera.WorldToScreenPoint(dto.position);
//RectTransformUtility.ScreenPointToLocalPointInRectangle(_uiView.CombatValRoot as RectTransform, screenPoint, UICamera, out var localPoint);
hpAddView?.ShowValue(dto.hpValue, localPoint, dto.elementType, () =>
{
Context.Asset.Recycle(hpAddView);
});
});
}
///
/// 保存时间
///
///
/// 延迟播放时间,单位:毫秒
private void SaveHpAddTime(long entityId, out int delay)
{
delay = 0;
var curTime = Context.Time.GetNowTime();
if (_hpAddLastTimeMap.TryGetValue(entityId, out var lastTime))
{
const int interval = 200;
var playTime = lastTime + interval;
if (playTime > curTime)
{
lastTime = playTime;
delay = (int)(playTime - curTime);
}
else
{
lastTime = curTime;
}
}
else
{
lastTime = curTime;
}
_hpAddLastTimeMap[entityId] = lastTime;
}
private void LoadUIView()
{
var loadAsync = Context.Asset.LoadEntity(AddressableDefine.mainmapui, Context.VM.UIRoot);
_uiViewAsync = loadAsync;
loadAsync.On(_ =>
{
_uiViewAsync = null;
var uiView = loadAsync.Result;
if (uiView == null)
return;
_uiView = uiView;
uiView.RefreshChapter(_chapterId);
});
}
#region 副本进度相关
public void RefreshChapter(int chapterId)
{
if (_chapterId == chapterId) return;
_chapterId = chapterId;
_uiView?.RefreshChapter(chapterId);
}
#endregion
}
}