基于ET的回合制战棋-技能部分
前言
目前技能设计大类分为普通技能和终结技,且技能物件都基于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
16public 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
EffectTrack
用于动态加载特效AB包并生成特效,在对应PlayableAsset结束时会进行特效的回收和销毁
支持对象池生成
可获取同Timline中其他轨道的binding GameObject,并获取其子对象作为生成位置参照
Track文件展示
PlayableAsset展示
分为四种生成模式,对应位置/参照物偏移/绑定为子物体/参照物局部偏移
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
30public 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函数对其进行构造操作
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 Asset中Remove Start Offset的勾选,这样就能让相机动画的初始位置得以生效。
技能
对技能的设计考虑到了client/Server的双端代码共用,因此采取了将技能拆封为Effect和Action两部分函数周期的方式。
- 离线模式下,client同时执行技能的Effect和Action生命周期
- 在线模式下,client仅执行Effect生命周期,关键的Action生命周期交由server进行处理,保证服务器的权威性