【博客节选】自定义 timeline track 与 PlayableBehaviour数据交互

注:软件版本Unity 6.0 + Timeline 1.8.7

作者:CSDN @ RingleaderWang
原文:《Unity第25期——Timeline结构及其源码浅析》
文章首发Github👍《Timeline结构及其源码浅析》

Bilibili 视频版👍👍《Timeline结构及其源码解析》https://www.bilibili.com/video/BV1bHjYzNE35

Behaviour 与 PlayableAsset的数据交互

我们在自定义Track 自定义PlayableAsset时,可能有这么个需求,Track或PlayableAsset自身需要拥有特殊属性,而且能在后面的生命周期中获取这个特殊属性。

比如我的技能系统用的SkillPlayableAsset,有个参数标注这个clip用于技能的哪个阶段,就需要SkiIlPhase这么一个参数,后面behaviour回调触发时就能根据这个参数针对性做处理。

Track或PlayableAsset自身需要拥有特殊属性的场景

这就是behaviour 与 playableAsset的数据交互问题。

如果你是官方设定的基础Playable,你可以在Playable上设置这么个特殊属性,create的时候都塞进去,生命周期回调时也能正常获取。但你自定义track,用的都是ScriptPlayable,没有额外参数,怎么办?那就是用PlayableBehaviour传参!

传参有两种方式,这同时也涉及到ScriptPlayable createPlayable的两种方式。

// T : class, IPlayableBehaviour, new()
public static ScriptPlayable<T> Create(PlayableGraph graph, int inputCount = 0)  
{  
  return new ScriptPlayable<T>(ScriptPlayable<T>.CreateHandle(graph, default (T), inputCount));  
}  
  
public static ScriptPlayable<T> Create(PlayableGraph graph, T template, int inputCount = 0)  
{  
  return new ScriptPlayable<T>(ScriptPlayable<T>.CreateHandle(graph, template, inputCount));  
}
带 new T() 的 ScriptPlayable 创建

如上ScriptPlayable 创建Playable时,可以带T template 参数,T就是实现了IPlayableBehaviour且有无参构造函数的类。

这样自定track或playableAsset在创建playable时就可以将含有特殊属性的T传进来,behaviour回调时就能获取到你设的特殊属性。

// 存在 XXPlayableBehaviour,内含param1、param2两个参数

public class XXPlayableAsset : PlayableAsset
{
	public XXPlayableBehaviour template = new XXPlayableBehaviour();
	public override Playable CreatePlayable (PlayableGraph graph, GameObject owner){
	   var playable = ScriptPlayable<XXPlayableBehaviour>.Create(graph,template);
	   return playable;
	}
}
XXPlayableAsset Inspector面板展示:
template
- param1
- param2

这样你在XXPlayableAsset Inspector就能展示XXPlayableBehaviour的两个参数,param1和param2,但不够好看,外面会套一层参数名,像下面这样:

解决方法有两个,一种是类似AudioTrack的处理方法,写个AudioTrackInspector手动提取出各个参数。另一个参考官方案例的自定义Attribute:NoFoldOut。

// Custom property drawer that draws all child properties inline
[CustomPropertyDrawer(typeof(NoFoldOutAttribute))]
public class NoFoldOutPropertyDrawer : PropertyDrawer
{
    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        if (!property.hasChildren)
            return base.GetPropertyHeight(property, label);
        property.isExpanded = true;
        return EditorGUI.GetPropertyHeight(property, label, true) -
               EditorGUI.GetPropertyHeight(property, label, false);
    }

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        if (!property.hasChildren)
            EditorGUI.PropertyField(position, property, label);
        else
        {
            SerializedProperty iter = property.Copy();
            var nextSibling = property.Copy();
            nextSibling.Next(false);
            property.Next(true);
            do
            {
                // We need to check against nextSibling to properly stop
                // otherwise we will draw properties that are not child of this
                // foldout.
                if (SerializedProperty.EqualContents(property, nextSibling))
                    break;
                float height = EditorGUI.GetPropertyHeight(property, property.hasVisibleChildren);
                position.height = height;
                EditorGUI.PropertyField(position, property, property.hasVisibleChildren);
                position.y = position.y + height;
            }
            while (property.NextVisible(false));
        }
    }
}

这样使用时给参数加[NoFoldOut]特性就能直接展示子属性了。

// 存在 XXPlayableBehaviour,内含param1、param2两个参数
public class XXPlayableAsset : PlayableAsset
{
	[NoFoldOut]
	public XXPlayableBehaviour template = new XXPlayableBehaviour();
	public override Playable CreatePlayable (PlayableGraph graph, GameObject owner){
	   var playable = ScriptPlayable<XXPlayableBehaviour>.Create(graph,template);
	   return playable;
	}
}

使用 default (T) 的 ScriptPlayable 创建

如果你使用 default (T) 创建,意味着你的这些特殊属性都变成默认值。

不过你也可以手动操作改变,如下代码所示,create完ScriptPlayable后,再手动赋值。

// 存在 XXPlayableBehaviour,内含param1、param2两个参数

public class XXPlayableAsset : PlayableAsset
{
	public override Playable CreatePlayable (PlayableGraph graph, GameObject owner)
	{
	   var playable = ScriptPlayable<XXPlayableBehaviour>.Create(graph);
	   var xxPlayableBehaviour = playable.GetBehaviour();
	   xxPlayableBehaviour.param1 = value1;
	   xxPlayableBehaviour.param2 = value2;
	   return playable;
	}
}

不过这种在Asset还要再申明一遍param,冗杂,所以推荐用第一种。

ExposedReference用法

因为Asset不能引用scene场景中的对象,但如果你非要引用也不是不可以,Timeline提供了ExposedReference方法让你能在Behaviour回调中获取场景中的对象。

public class XXPlayableBehaviour : PlayableBehaviour
{
	public ExposedReference<Transform> exposedTransform;
	public override void OnGraphStart(Playable playable){
		Transform transform = exposedTransform.Resolve(playable.GetGraph().GetResolver());  
		Debug.Log("exposedTransform.Resolve(playable.GetGraph().GetResolver()):"+transform.position);
		Debug.Log("gameobject name:" + transform.gameObject.name);
	
	}
}

public class XXPlayableAsset : PlayableAsset
{
	public XXPlayableBehaviour template = new XXPlayableBehaviour();
	public override Playable CreatePlayable (PlayableGraph graph, GameObject owner){
	   var playable = ScriptPlayable<XXPlayableBehaviour>.Create(graph,template);
	   return playable;
	}
}

注意使用时,一定要从点击挂载PlayableDirector的对象对应的timeline窗口操作。

ExposedReference用法

运行时可以正常打印,但发现打印的对象position数据有问题,似乎有(0.22, 1.28, -1.66)的偏差,不清楚原因,暂时还是不要用ExposedReference

ExposedReference用法有待进一步验证
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值