前言

​ 目前技能设计大类分为普通技能和终结技,且技能物件都基于BaseSkillItem,两种的思路都会在之后进行介绍,同时也会介绍技能的具体生命周期与针对服务器/客户端双端使用的函数分发处理。

终结技

​ 因为考虑到终结技需要营造出的效果,需要配合相机Animation、受击方Animation、音效、UI显示、特效生成的情况。这时就想到了timeline这种方式,而将具体的伤害数值处理延后到Timeline播放之后。

Timeline轨道拓展

​ 根据具体的使用情况,我拓展了四类轨道,AnimationValueTrack、EffectTrack、TransformTrack、UITrack

  • Timeline的本质是通过TrackAsset创建出对应的PlayableGraph(内含多种Playable),而后进行通过PlayableDirector进行播放
  • 对Timeline中Track的拓展需要进行TrackAsset(轨道文件)、PlayableAsset(轨道内文件)、PlayableBehaviour(轨道内文件在PlayableGraph播放时的具体回调,具有OnGraphStart,OnBehaviourPlay、OnBehaviourPause等多种生命周期函数)

AnimationValueTrack

  • 主要是可以对多个Animator的Parameter同时进行设置,采用AnimatorValues的ScriptableObject对需要操作的Animators进行存储,并且可以将trackAsset中绑定的AnimatorValues传递给在这个track中的所有PlayableAsset。

  • 具体的Behaviour关键周期

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public override void OnBehaviourPlay(Playable playable, FrameData info)
    {
    if (!this.isAlreadyPlay)
    {
    this.SetAnimatorsParams(this.animatorValues,this.beginAnimatorParam);
    this.isAlreadyPlay = true;
    }
    }

    public override void OnBehaviourPause(Playable playable, FrameData info)
    {
    if (this.isAlreadyPlay)
    {
    this.SetAnimatorsParams(this.animatorValues,this.endAnimatorParam);
    }
    }
  • 可在Timeline的PlayableAsset中设置其触发的Parameter
    image-20220302185233638

EffectTrack

  • 用于动态加载特效AB包并生成特效,在对应PlayableAsset结束时会进行特效的回收和销毁

  • 支持对象池生成

  • 可获取同Timline中其他轨道的binding GameObject,并获取其子对象作为生成位置参照

  • Track文件展示
    image-20220302191132624

  • PlayableAsset展示
    分为四种生成模式,对应位置/参照物偏移/绑定为子物体/参照物局部偏移

    image-20220412102552412

TransformTrack

  • 作为Transform的暂存轨道,可以动态设置Binding GameObject的transform位置
  • 主要是为了记录技能释放目标点

UITrack

  • 作为UI消息分发轨道,通知DlgShowDmg的UI界面进行终结技伤害的更新显示

  • 轨道内的PlayableAsset通过其对应的APlayableAssetBuilder进行构造

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    [PlayableAssetBuilderAttribute(typeof(UIDamageAsset))]
    public class UIDamageBuilder:APlayableAssetBuilder
    {
    public override void BuildData(TimelineComponent timelineCompoent, PlayableAsset playableAsset, params object[] _params)
    {
    UIDamageAsset asset = playableAsset as UIDamageAsset;
    asset._DamageAction += () =>
    {
    EventMessageComponent.Instance.SendMessage(MessageEventNames.UPDATE_DAMAGE_MSG, timelineCompoent, (float)_params[0]); //发布UI信息更新通知
    };
    }
    }

Timeline的builder构造模式

​ 上面的许多Timeline都需要在调用的时候动态设置其binding GameObject 与相关回调函数,因此对于timeline的构造我采用了builder的方式

  • 在TimelineComponent组件的awake过程中会收集所有打上TrackAssetBuilderAttribute和PlayableAssetBuilderAttribute的分发抽象类,在需要对对应的asset进行处理时分发

    Builder加载:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    public static void LoadBuilder(this TimelineComponent self)
    {
    var builders = Game.EventSystem.GetTypes(typeof (TrackAssetBuilderAttribute));
    foreach (var type in builders)
    {
    object[] attrs = type.GetCustomAttributes(typeof (TrackAssetBuilderAttribute), false);
    if (attrs.Length == 0)
    {
    continue;
    }

    TrackAssetBuilderAttribute builderAttribute = attrs[0] as TrackAssetBuilderAttribute;
    ATrackAssetBuilder builder = Activator.CreateInstance(type) as ATrackAssetBuilder;
    self.type2TrackAssetBuilder.Add(builderAttribute.trackBehaviourType,builder);
    }

    builders = Game.EventSystem.GetTypes(typeof (PlayableAssetBuilderAttribute));
    foreach (var type in builders)
    {
    object[] attrs = type.GetCustomAttributes(typeof (PlayableAssetBuilderAttribute), false);
    if (attrs.Length == 0)
    {
    continue;
    }

    PlayableAssetBuilderAttribute builderAttribute = attrs[0] as PlayableAssetBuilderAttribute;
    APlayableAssetBuilder builder = Activator.CreateInstance(type) as APlayableAssetBuilder;
    self.type2PlayableAssetBuilder.Add(builderAttribute.trackBehaviourType,builder);
    }
    }
  • 以某Timeline中的UITrack作为例子,在对TrackAsset调用BuildTrackAsset并传入对应参数时会自动分发对应的builder函数对其进行构造操作

    image-20220302192424642

    UITrack对应的TrackAssetBuilder:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    [TrackAssetBuilderAttribute(typeof(UITrack))]
    public class UITrackBuilder:ATrackAssetBuilder
    {
    /// <summary>
    /// 构造数据
    /// </summary>
    /// <param name="timelineComponent"></param>
    /// <param name="behaviour"></param>
    /// <param name="_params"></param>
    public override void BuildData(TimelineComponent timelineComponent, TrackAsset trackAsset, params object[] _params)
    {
    UITrack uiTrack = trackAsset as UITrack;
    //获取所有clips
    List<TimelineClip> list= new List<TimelineClip>(uiTrack.GetClips());
    int count = 0;
    float[] damages = _params[0] as float[];
    foreach (var clip in list)
    {
    if (clip.asset is UIDamageAsset asset)
    {
    timelineComponent.BuildPlayableAsset(asset,damages[count++]);
    }
    }
    }
    }

使用注意点

  • 在使用相机动画Camera_Anim时,需要去取消Animation Playable AssetRemove Start Offset的勾选,这样就能让相机动画的初始位置得以生效。
    image-20220315151525945

技能

​ 对技能的设计考虑到了client/Server的双端代码共用,因此采取了将技能拆封为Effect和Action两部分函数周期的方式。

  • 离线模式下,client同时执行技能的Effect和Action生命周期
  • 在线模式下,client仅执行Effect生命周期,关键的Action生命周期交由server进行处理,保证服务器的权威性