123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- using System;
- using System.Collections.Generic;
- using UnityEngine;
- 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.Battle.Components
- {
- /// <summary>
- /// 特效播放上下文
- /// </summary>
- public interface IVfxContext
- {
- IMapAssetModule Asset { get; }
- ITimeModule Time { get; }
- /// <summary>
- /// 世界节点,不是则返回空
- /// 只有世界节点才能播放VfxFollowType.World的特效
- /// 每个地图只能有一个世界节点
- /// </summary>
- Transform WorldTr { get; }
- Transform CenterTr { get; }
- /// <summary>
- /// 施法点,没有则返回空
- /// </summary>
- Transform CastTr { get; }
- }
- /// <summary>
- /// 特效播放组件
- /// TODO 世界跟随类型需要将特效转到地图播放,以防止角色死亡时特效播放被打断
- /// </summary>
- public class VfxComponent : Component<IVfxContext>
- {
- class VfxPlayingDto : IReference
- {
- public IAsync loadAsync;
- public ITimer timer;
- public GameObject vfxGo;
- void IReference.Clear()
- {
- loadAsync = null;
- timer = null;
- vfxGo = null;
- }
- }
- private Dictionary<VfxPlayingDto, VfxArgs> _playingVfxMap = new Dictionary<VfxPlayingDto, VfxArgs>();
- protected override void OnEnable(object intent)
- {
- if (Context.WorldTr != null)
- {
- EventSingle.Instance.AddListener(EventDefine.VfxComponentWorldVfx, OnWorldVfx);
- }
- }
- protected override void OnDisable()
- {
- if (Context.WorldTr != null)
- {
- EventSingle.Instance.RemoveListener(EventDefine.VfxComponentWorldVfx, OnWorldVfx);
- }
- }
- protected override void OnDispose()
- {
- Stop();
- }
- public void Play(VfxArgs args)
- {
- Assert.IsTrue(args != null, "特效播放参数不能为空.");
- Assert.IsFalse(string.IsNullOrEmpty(args.vfxName), "特效名字不能为空.");
- Assert.IsTrue(args.duration > 0, $"特效播放时长必须大于零. Name:{args.vfxName}");
- if (args.followType == EVfxFollowType.World && Context.WorldTr == null)
- {
- EventSingle.Instance.Notify(EventDefine.VfxComponentWorldVfx, args);
- return;
- }
- var dto = AcquireDto(args);
- void DelayPlay()
- {
- var loadAsync = Context.Asset.LoadAsync<GameObject>(args.vfxName);
- dto.loadAsync = loadAsync;
- loadAsync.On(_ =>
- {
- dto.loadAsync = null;
- var vfxGo = loadAsync.Result;
- if (vfxGo == null)
- {
- RecycleDto(dto);
- args.onFinish.SafeInvoke();
- RecycleArgs(args);
- return;
- }
- dto.vfxGo = vfxGo;
- SetParent(vfxGo.transform, args.followType);
- vfxGo.SetActive(true);
- args.action?.Start(vfxGo.transform);
- dto.timer = Context.Time.AddDelayTimer(args.duration, () =>
- {
- dto.timer = null;
- dto.vfxGo = null;
- //回收GameObject
- Context.Asset.Recycle(vfxGo);
- //回收dto
- RecycleDto(dto);
- args.onFinish.SafeInvoke();
- var next = args.next;
- if (next != null)
- {
- args.next = null;
- //播放下一个
- Play(next);
- }
- RecycleArgs(args);
- });
- });
- }
- if (args.delay > 0)
- {
- dto.timer = Context.Time.AddDelayTimer(args.delay, () =>
- {
- dto.timer = null;
- DelayPlay();
- });
- }
- else
- {
- DelayPlay();
- }
- }
- public void Stop()
- {
- foreach (var item in _playingVfxMap)
- {
- RecycleDto(item.Key, false);
- RecycleArgs(item.Value);
- }
- _playingVfxMap.Clear();
- }
- private void SetParent(Transform vfxTr, EVfxFollowType followType)
- {
- Transform parent;
- switch (followType)
- {
- case EVfxFollowType.World:
- parent = Context.WorldTr;
- break;
- case EVfxFollowType.CastPoint:
- parent = Context.CastTr != null ? Context.CastTr : Context.CenterTr;
- break;
- default:
- parent = Context.CenterTr;
- break;
- }
- vfxTr.SetParent(parent, false);
- if (followType != EVfxFollowType.World)
- {
- vfxTr.localPosition = Vector3.zero;
- }
- //TODO 技能特效需要缩小尺寸
- vfxTr.localScale = Vector3.one * 0.7f;
- }
- //public VfxArgs AcquireArgs()
- //{
- // return ObjectPool.Acquire<VfxArgs>();
- //}
- public void RecycleArgs(VfxArgs args)
- {
- if (args == null)
- return;
- if (args.next != null)
- {
- RecycleArgs(args.next);
- }
- if (args.action != null)
- {
- ObjectPool.Recycle(args.action);
- args.action = null;
- }
- ObjectPool.Recycle(args);
- }
- private VfxPlayingDto AcquireDto(VfxArgs args)
- {
- var dto = ObjectPool.Acquire<VfxPlayingDto>();
- _playingVfxMap.Add(dto, args);
- return dto;
- }
- private void RecycleDto(VfxPlayingDto dto, bool removeMap = true)
- {
- dto.loadAsync?.RemoveAll();
- dto.timer?.Cancel();
- if (dto.vfxGo != null)
- {
- Context.Asset.Recycle(dto.vfxGo);
- }
- if (removeMap)
- {
- _playingVfxMap.Remove(dto);
- }
- ObjectPool.Recycle(dto);
- }
- #region 事件监听
- private void OnWorldVfx(int eventId, object args)
- {
- var vfxArgs = args as VfxArgs;
- Play(vfxArgs);
- }
- #endregion
- }
- }
|