MapUIComponent.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. using FairyGUI;
  2. using FL.Battle;
  3. using FL.Map.UI;
  4. using FL.Nodes.GameMain;
  5. using System.Collections.Generic;
  6. using UnityEngine;
  7. using XGame;
  8. using XGame.Database;
  9. using XGame.Framework.Asyncs;
  10. using XGame.Framework.Components;
  11. using XGame.Framework.Interfaces;
  12. using XGame.Framework.Map;
  13. using XGame.Framework.Time;
  14. namespace FL.Map.TestMainMap
  15. {
  16. public interface IMapUIContext
  17. {
  18. IMapAssetModule Asset { get; }
  19. ITimeModule Time { get; }
  20. TestMainMapVM VM { get; }
  21. }
  22. /// <summary>
  23. /// 地图用UI
  24. /// </summary>
  25. public class MapUIComponent : Component<IMapUIContext>, ILateUpdate
  26. {
  27. private MainMapUIView _uiView;
  28. private IAsync _uiViewAsync;
  29. /// <summary>
  30. /// 玩家、怪物血条
  31. /// </summary>
  32. private Dictionary<long, EntityBattleInfoView> _entityViewsMap = new Dictionary<long, EntityBattleInfoView>();
  33. /// <summary>
  34. /// 飘血计时
  35. /// 同一个Entity的飘血需要有200毫秒间隔
  36. /// </summary>
  37. private Dictionary<long, long> _hpAddLastTimeMap = new Dictionary<long, long>();
  38. /// <summary>
  39. /// TODO
  40. /// </summary>
  41. private Camera UICamera => StageCamera.main;
  42. private int _chapterId;
  43. protected override void OnEnable(object intent)
  44. {
  45. EventSingle.Instance.AddListener(EventDefine.GameMainMapRemoveEntity, OnRemoveEntity);
  46. EventSingle.Instance.AddListener(EventDefine.GameMainMapStartMask, OnStartMask);
  47. EventSingle.Instance.AddListener(EventDefine.GameMainMapHpAdd, OnHpAdd);
  48. EventSingle.Instance.AddListener(EventDefine.GameMainMapBossStart, OnBossStart);
  49. LoadUIView();
  50. }
  51. protected override void OnDisable()
  52. {
  53. EventSingle.Instance.RemoveListener(EventDefine.GameMainMapRemoveEntity, OnRemoveEntity);
  54. EventSingle.Instance.RemoveListener(EventDefine.GameMainMapStartMask, OnStartMask);
  55. EventSingle.Instance.RemoveListener(EventDefine.GameMainMapHpAdd, OnHpAdd);
  56. EventSingle.Instance.RemoveListener(EventDefine.GameMainMapBossStart, OnBossStart);
  57. if (_uiView != null)
  58. {
  59. Context.Asset.Recycle(_uiView);
  60. _uiView = null;
  61. }
  62. if (_uiViewAsync != null)
  63. {
  64. _uiViewAsync.RemoveAll();
  65. _uiViewAsync = null;
  66. }
  67. ClearEntities(true);
  68. _chapterId = 0;
  69. }
  70. protected override void OnDispose()
  71. {
  72. }
  73. void ILateUpdate.LateUpdate(int millisecond)
  74. {
  75. if (_entityViewsMap.Count > 0)
  76. {
  77. var cameraMoving = Context.VM.Camera.IsMoving;
  78. foreach (var view in _entityViewsMap.Values)
  79. {
  80. if ((cameraMoving || view.Master.IsMoving) && view.IsMoveable)
  81. {
  82. view.LocalPosition = WorldToLocal(view.Master.UIPoint.position, _uiView.PlayerRoot);
  83. }
  84. view.RefreshBuffs();
  85. }
  86. }
  87. _uiView?.LateUpdate(millisecond);
  88. }
  89. /// <summary>
  90. /// 世界坐标转指定UI节点的相对坐标
  91. /// </summary>
  92. /// <param name="position"></param>
  93. /// <param name="parent"></param>
  94. /// <returns></returns>
  95. private Vector2 WorldToLocal(Vector3 position, Transform parent)
  96. {
  97. var screenPoint = Context.VM.Camera.WorldToScreenPoint(position);
  98. RectTransformUtility.ScreenPointToLocalPointInRectangle(parent as RectTransform, screenPoint, UICamera, out var localPoint);
  99. return localPoint;
  100. }
  101. public void AddEntity(ITarget master)
  102. {
  103. if (_uiView == null)
  104. {
  105. if (_uiViewAsync != null)
  106. {
  107. _uiViewAsync.On(_ =>
  108. {
  109. LoadEntityView(master);
  110. });
  111. }
  112. else
  113. {
  114. Log.Error($"MainMapUI不能为空.");
  115. }
  116. }
  117. else
  118. {
  119. LoadEntityView(master);
  120. }
  121. }
  122. public void RefreshEntity(long entityId)
  123. {
  124. if (_entityViewsMap.TryGetValue(entityId, out var view))
  125. {
  126. view.RefreshHp();
  127. }
  128. }
  129. private void LoadEntityView(ITarget master)
  130. {
  131. GetEntityAddressable(master, out var addressable, out var parent, out var isBoss);
  132. var viewAsync = Context.Asset.LoadEntity<EntityBattleInfoView>(addressable, parent);
  133. viewAsync.On(_ =>
  134. {
  135. var view = viewAsync.Result;
  136. if (view == null)
  137. return;
  138. if (master.IsDead)
  139. {
  140. Log.Debug($"EntityBattleInfoView 加载完成,Entity已经死亡. Id:{master.Entity.EntityId}");
  141. Context.Asset.Recycle(view);
  142. return;
  143. }
  144. view.Master = master;
  145. view.IsMoveable = !isBoss;
  146. view.LocalPosition = isBoss ? Vector3.zero : WorldToLocal(master.UIPoint.position, _uiView.PlayerRoot);
  147. _entityViewsMap.Add(view.Master.Entity.EntityId, view);
  148. });
  149. }
  150. private void GetEntityAddressable(ITarget master, out string addressableName, out Transform parent, out bool isBoss)
  151. {
  152. isBoss = false;
  153. if (master.Entity.EntityType == EEntityType.Monster)
  154. {
  155. var table = MonsterTableRepo.Get(master.Entity.TableId);
  156. if (table.Type == 2)
  157. {
  158. addressableName = AddressableDefine.bossbattleinfo;
  159. parent = _uiView.BossRoot;
  160. isBoss = true;
  161. }
  162. else
  163. {
  164. addressableName = AddressableDefine.monsterbattleinfo;
  165. parent = _uiView.MonsterRoot;
  166. }
  167. }
  168. else
  169. {
  170. addressableName = AddressableDefine.playerbattleinfo;
  171. parent = _uiView.PlayerRoot;
  172. }
  173. }
  174. private void OnRemoveEntity(int eventId, object args)
  175. {
  176. var entityId = (long)args;
  177. if (_entityViewsMap.TryGetValue(entityId, out var view))
  178. {
  179. if (view.Master.Entity.EntityType == EEntityType.Player)
  180. { // 玩家的血条不移除
  181. return;
  182. }
  183. _entityViewsMap.Remove(entityId);
  184. Context.Asset.Recycle(view);
  185. }
  186. _hpAddLastTimeMap.Remove(entityId);
  187. }
  188. private void OnStartMask(int eventId, object args)
  189. {
  190. var sign = (EMapCombatSign)args; //0表示战斗胜利,1表示普通战斗失败,2表示boss战斗失败
  191. if ( sign != EMapCombatSign.Success)
  192. { // 玩家死亡,失败,移除所有怪物的血条
  193. ClearEntities(false);
  194. if (sign is EMapCombatSign.FailedBoss)
  195. {
  196. _uiView?.SetBossFailed(true);
  197. }
  198. }
  199. }
  200. private void OnHpAdd(int eventId, object args)
  201. {
  202. PlayHpAdd((HpAddDto)args);
  203. }
  204. private void OnBossStart(int eventId, object args)
  205. {
  206. //var chapterId = (int)args;
  207. _uiView?.StartBossTime();
  208. }
  209. private void ClearEntities(bool includePlayer)
  210. {
  211. EntityBattleInfoView player = null;
  212. foreach (var entity in _entityViewsMap.Values)
  213. {
  214. if (!includePlayer && entity.Master.Entity.EntityType == EEntityType.Player)
  215. {
  216. player = entity;
  217. continue;
  218. }
  219. Context.Asset.Recycle(entity);
  220. }
  221. _entityViewsMap.Clear();
  222. _hpAddLastTimeMap.Clear();
  223. if (player != null)
  224. {
  225. _entityViewsMap.Add(player.Master.Entity.EntityId, player);
  226. }
  227. }
  228. private void PlayHpAdd(HpAddDto dto)
  229. {
  230. if (_uiView == null)
  231. return;
  232. RefreshEntity(dto.entityId);
  233. SaveHpAddTime(dto.entityId, out var delay);
  234. if (delay > 0)
  235. {
  236. var timer = Context.Time.AddDelayTimer(delay, () =>
  237. {
  238. LoadHpAddView(dto);
  239. });
  240. }
  241. else
  242. {
  243. LoadHpAddView(dto);
  244. }
  245. }
  246. private void LoadHpAddView(HpAddDto dto)
  247. {
  248. var viewAsync = Context.Asset.LoadEntity<HpAddEntityView>(AddressableDefine.uihpadd, _uiView.CombatValRoot);
  249. viewAsync.On(_ =>
  250. {
  251. var hpAddView = viewAsync.Result;
  252. if (hpAddView == null)
  253. return;
  254. var localPoint = WorldToLocal(dto.position, _uiView.CombatValRoot);
  255. //var screenPoint = Context.VM.Camera.WorldToScreenPoint(dto.position);
  256. //RectTransformUtility.ScreenPointToLocalPointInRectangle(_uiView.CombatValRoot as RectTransform, screenPoint, UICamera, out var localPoint);
  257. hpAddView?.ShowValue(dto.hpValue, localPoint, dto.elementType, () =>
  258. {
  259. Context.Asset.Recycle(hpAddView);
  260. });
  261. });
  262. }
  263. /// <summary>
  264. /// 保存时间
  265. /// </summary>
  266. /// <param name="entityId"></param>
  267. /// <param name="delay">延迟播放时间,单位:毫秒</param>
  268. private void SaveHpAddTime(long entityId, out int delay)
  269. {
  270. delay = 0;
  271. var curTime = Context.Time.GetNowTime();
  272. if (_hpAddLastTimeMap.TryGetValue(entityId, out var lastTime))
  273. {
  274. const int interval = 200;
  275. var playTime = lastTime + interval;
  276. if (playTime > curTime)
  277. {
  278. lastTime = playTime;
  279. delay = (int)(playTime - curTime);
  280. }
  281. else
  282. {
  283. lastTime = curTime;
  284. }
  285. }
  286. else
  287. {
  288. lastTime = curTime;
  289. }
  290. _hpAddLastTimeMap[entityId] = lastTime;
  291. }
  292. private void LoadUIView()
  293. {
  294. var loadAsync = Context.Asset.LoadEntity<MainMapUIView>(AddressableDefine.mainmapui, Context.VM.UIRoot);
  295. _uiViewAsync = loadAsync;
  296. loadAsync.On(_ =>
  297. {
  298. _uiViewAsync = null;
  299. var uiView = loadAsync.Result;
  300. if (uiView == null)
  301. return;
  302. _uiView = uiView;
  303. uiView.RefreshChapter(_chapterId);
  304. });
  305. }
  306. #region 副本进度相关
  307. public void RefreshChapter(int chapterId)
  308. {
  309. if (_chapterId == chapterId) return;
  310. _chapterId = chapterId;
  311. _uiView?.RefreshChapter(chapterId);
  312. }
  313. #endregion
  314. }
  315. }