Unity Timeline从入门到精通(六):扩展Timeline

声明:以Default Playables插件中提供的LightControl为例,讲解怎么去扩展Timeline。

自定义行为:流程如下所示:
1.创建一个继承自PlayableBehaviour类型的公有序列化行为类型LightControlBehaviour。
2.在LightControlBehaviour类型中添加需要显示在检视面板中的公有属性。
3.参考代码如下所示:

using System;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;

[Serializable]
public class LightControlBehaviour : PlayableBehaviour
{
    
    
    public Color color = Color.white;
    public float intensity = 1f;
    public float bounceIntensity = 1f;
    public float range = 10f;
}

自定义片段:流程如下所示:
1.创建一个继承自PlayableAsset类型以及ITimelineClipAsset接口的公有序列化片段类型LightControlClip。
2.在LightControlClip类型中添加一个公有LightControlBehaviour类型对象。这样做具有以下好处:
2.1.该对象会在检视面板上暴露出来,同时也会暴露出该对象自身包含的公有属性。如图所示:
在这里插入图片描述
2.2.可以在该对象以及该对象的公有属性上通过Add Key菜单项来添加关键帧动画,从而对片段做更多的精细控制。如图所示:
在这里插入图片描述
2.3.由于不用做片段和行为之间公有属性的同步操作,所以代码会更加精简。
3.在LightControlClip类型中实现clipCaps属性。该属性的数值用来控制某些系统片段属性是否显示在检视面板上。
4.在LightControlClip类型中实现CreatePlayable抽象函数,并在该抽象函数内部创建可播放资源类型对象。流程如下:
4.1.将LightControlBehaviour类型作为ScriptPlayable类型的泛型参数。
4.2.将抽象函数中的接收的第一个参数以及添加的LightControlBehaviour类型对象一起传入并调用ScriptPlayable.Create函数,从而得到一个跟LightControlBehaviour类型的行为相绑定的可播放资源类型对象。
5.参考代码如下所示:

using System;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;

[Serializable]
public class LightControlClip : PlayableAsset, ITimelineClipAsset
{
    
    
    public LightControlBehaviour template = new LightControlBehaviour ();

    public ClipCaps clipCaps
    {
    
    
        get {
    
     return ClipCaps.Blending; }
    }

    public override Playable CreatePlayable (PlayableGraph graph, GameObject owner)
    {
    
    
        var playable = ScriptPlayable<LightControlBehaviour>.Create (graph, template);
        return playable;    
    }
}

自定义属性绘制:流程如下所示:
1.创建一个继承自PropertyDrawer类型的公有属性绘制类型LightControlDrawer。
2.在LightControlDrawer类型上加上CustomPropertyDrawer定制特性,用来接管在检视面板上如何绘制LightControlBehaviour类型中的公有属性。
3.在LightControlDrawer类型中实现GetPropertyHeight函数,用来指定要绘制的所有属性在检视面板中占用的总高度。
4.在LightControlDrawer类型中实现OnGUI函数,用来在检视面板上按照指定的顺序和位置来绘制属性。
5.参考代码如下所示:

using UnityEditor;
using UnityEngine;
using UnityEngine.Playables;

[CustomPropertyDrawer(typeof(LightControlBehaviour))]
public class LightControlDrawer : PropertyDrawer
{
    
    
    public override float GetPropertyHeight (SerializedProperty property, GUIContent label)
    {
    
    
        int fieldCount = 4;
        return fieldCount * EditorGUIUtility.singleLineHeight;
    }

    public override void OnGUI (Rect position, SerializedProperty property, GUIContent label)
    {
    
    
        SerializedProperty colorProp = property.FindPropertyRelative("color");
        SerializedProperty intensityProp = property.FindPropertyRelative("intensity");
        SerializedProperty bounceIntensityProp = property.FindPropertyRelative("bounceIntensity");
        SerializedProperty rangeProp = property.FindPropertyRelative("range");

        Rect singleFieldRect = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);
        EditorGUI.PropertyField(singleFieldRect, colorProp);
        
        singleFieldRect.y += EditorGUIUtility.singleLineHeight;
        EditorGUI.PropertyField(singleFieldRect, intensityProp);
        
        singleFieldRect.y += EditorGUIUtility.singleLineHeight;
        EditorGUI.PropertyField(singleFieldRect, bounceIntensityProp);
        
        singleFieldRect.y += EditorGUIUtility.singleLineHeight;
        EditorGUI.PropertyField(singleFieldRect, rangeProp);
    }
}

6.检视面板上的绘制效果如图所示:
在这里插入图片描述
自定义混合器:流程如下所示:
1.创建一个继承自PlayableBehaviour类型的公有混合器类型LightControlMixerBehaviour。
2.在LightControlMixerBehaviour类型中重写ProcessFrame函数。该函数具有以下特性:
2.1.该函数会在片段的每帧中进行调用。
2.2.该函数的第三个参数playerData实际上就是轨道绑定的游戏对象。
2.3.该函数的第一个参数playable实际上就是轨道对象。该对象常用的API如下所示:
2.3.1.GetInputCount函数用来获取轨道上片段的总个数(非混合模式就返回0)。
2.3.2.GetInputWeight函数用来获取指定片段的权重值。
2.3.3.GetInput函数用来获取指定可播放资源类型对象。可以通过调用该可播放资源类型对象的GetBehaviour函数来获取关联的行为对象。
3.在LightControlMixerBehaviour类型中重写OnPlayableDestroy函数,从而在片段生命周期结束时,交由开发者做更多的逻辑控制。
4.参考代码如下所示:

using System;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;

public class LightControlMixerBehaviour : PlayableBehaviour
{
    
    
    Color m_DefaultColor;
    float m_DefaultIntensity;
    float m_DefaultBounceIntensity;
    float m_DefaultRange;

    Light m_TrackBinding;
    bool m_FirstFrameHappened;

    public override void ProcessFrame(Playable playable, FrameData info, object playerData)
    {
    
    
        m_TrackBinding = playerData as Light;

        if (m_TrackBinding == null)
            return;

        if (!m_FirstFrameHappened)
        {
    
    
            m_DefaultColor = m_TrackBinding.color;
            m_DefaultIntensity = m_TrackBinding.intensity;
            m_DefaultBounceIntensity = m_TrackBinding.bounceIntensity;
            m_DefaultRange = m_TrackBinding.range;
            m_FirstFrameHappened = true;
        }

        int inputCount = playable.GetInputCount ();

        Color blendedColor = Color.clear;
        float blendedIntensity = 0f;
        float blendedBounceIntensity = 0f;
        float blendedRange = 0f;
        float totalWeight = 0f;
        float greatestWeight = 0f;
        int currentInputs = 0;

        for (int i = 0; i < inputCount; i++)
        {
    
    
            float inputWeight = playable.GetInputWeight(i);
            ScriptPlayable<LightControlBehaviour> inputPlayable = (ScriptPlayable<LightControlBehaviour>)playable.GetInput(i);
            LightControlBehaviour input = inputPlayable.GetBehaviour ();
            
            blendedColor += input.color * inputWeight;
            blendedIntensity += input.intensity * inputWeight;
            blendedBounceIntensity += input.bounceIntensity * inputWeight;
            blendedRange += input.range * inputWeight;
            totalWeight += inputWeight;

            if (inputWeight > greatestWeight)
            {
    
    
                greatestWeight = inputWeight;
            }

            if (!Mathf.Approximately (inputWeight, 0f))
                currentInputs++;
        }

        m_TrackBinding.color = blendedColor + m_DefaultColor * (1f - totalWeight);
        m_TrackBinding.intensity = blendedIntensity + m_DefaultIntensity * (1f - totalWeight);
        m_TrackBinding.bounceIntensity = blendedBounceIntensity + m_DefaultBounceIntensity * (1f - totalWeight);
        m_TrackBinding.range = blendedRange + m_DefaultRange * (1f - totalWeight);
    }

    public override void OnPlayableDestroy (Playable playable)
    {
    
    
        m_FirstFrameHappened = false;

        if(m_TrackBinding == null)
            return;

        m_TrackBinding.color = m_DefaultColor;
        m_TrackBinding.intensity = m_DefaultIntensity;
        m_TrackBinding.bounceIntensity = m_DefaultBounceIntensity;
        m_TrackBinding.range = m_DefaultRange;
    }
}

自定义轨道:流程如下所示:
1.创建一个继承自TrackAsset类型的公有轨道类型LightControlTrack。
2.在LightControlTrack类型上不添加TrackColor定制特性时,轨道以及资源片段的彩色强调线为白色。
3.在LightControlTrack类型上添加TrackColor定制特性时,轨道以及资源片段的彩色强调线为指定的颜色。
4.在LightControlTrack类型上不添加TrackClipType定制特性时,轨道上不能添加任何类型片段。
5.在LightControlTrack类型上添加TrackClipType定制特性时,轨道上只能添加指定类型的片段。
6.在LightControlTrack类型上不添加TrackBindingType定制特性时,轨道作用于所有的游戏对象。
7.在LightControlTrack类型上添加TrackBindingType定制特性时,轨道只能作用于指定类型的游戏对象。
8.在LightControlTrack类型里重写CreateTrackMixer函数来创建可播放资源类型对象。流程如下:
8.1.将LightControlMixerBehaviour类型作为ScriptPlayable类型的泛型参数。
8.2.将CreateTrackMixer函数中的接收的第一个参数以及第三个参数一起传入并调用ScriptPlayable.Create函数,从而得到一个跟LightControlMixerBehaviour类型的混合器相绑定的可播放资源类型对象。
9.在LightControlTrack类型里重写GatherProperties函数,用来表示Timeline处于预览模式时哪些属性将被修改。
10.参考代码如下所示:

using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
using System.Collections.Generic;

[TrackColor(0.9454092f, 0.9779412f, 0.3883002f)]
[TrackClipType(typeof(LightControlClip))]
[TrackBindingType(typeof(Light))]
public class LightControlTrack : TrackAsset
{
    
    
    public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
    {
    
    
        return ScriptPlayable<LightControlMixerBehaviour>.Create (graph, inputCount);
    }

    public override void GatherProperties(PlayableDirector director, IPropertyCollector driver)
    {
    
    
#if UNITY_EDITOR
       Light trackBinding = director.GetGenericBinding(this) as Light;
       if (trackBinding == null)
           return;
       driver.AddFromName<Light>(trackBinding.gameObject, "m_Color");
       driver.AddFromName<Light>(trackBinding.gameObject, "m_Intensity");
       driver.AddFromName<Light>(trackBinding.gameObject, "m_Range");
       driver.AddFromName<Light>(trackBinding.gameObject, "m_BounceIntensity");
#endif
        base.GatherProperties(director, driver);
    }
}

Timeline Playable Wizard:它是Default Playables插件中提供的向导窗口。具有以下特性:
1.该窗口用来在扩展Timeline时,自动创建模板文件,从而节省开发者时间。
2.该窗口中包含以下属性:
2.1.Show Help属性:是否显示帮助提示文本。
2.2.Reset属性:重置用户设置。
2.3.Create属性:按照指定的用户设置,创建模板文件。
2.4.Playable Name属性:可播放资源类型名称。它首先会创建一个指定名称的目录;然后在目录里面创建以该名称作为开头,Track、MixerBehaviour、Clip、Behaviour作为结尾的四个模板文件。
2.5.Standard Blend Playable属性:是否创建标准混合的可播放资源类型。不选择该属性时,就交给开发者自己在去实现混合逻辑;选择该属性时,就会使用标准的混合逻辑,并且自动选择Create Draw?属性。
2.6.Track Binding Type属性:轨道绑定的游戏对象类型。不指定时作用于全部游戏对象;指定时就作用于指定类型游戏对象,并且在混合器的ProcessFrame函数中做判空处理。
2.7.Default Values属性:只有在选择Standard Blend Playable属性时才显示该属性。用来表示默认的绑定类型对象。
2.8.Standard Blend Playable Properties属性:只有在选择Standard Blend Playable属性时才显示该属性。用来在行为类型里面添加Track Binding Type属性中绑定的游戏对象类型身上的组件类型变量。
2.9.Exposed References属性:只有在没有选择Standard Blend Playable属性时才显示该属性。该属性具有以下功能:
2.9.1.在行为类型中添加暴露到检视面板上的数据类型变量。
2.9.2.在片段类型中添加暴露到检视面板中的导出引用类型变量。
2.9.3.在片段类型的CreatePlayable函数中将导出引用类型变量赋值给行为类型中对应的数据类型变量。
2.10.Behaviour Variables属性:只有在没有选择Standard Blend Playable属性时才显示该属性。用来在行为类型中添加暴露到检视面板上的数据类型变量。
2.11.Clip Caps属性:只有在没有选择Standard Blend Playable属性时才显示该属性。用来设置片段的检视面板上哪些系统属性可以显示。
2.12.Track Color属性:用来设置轨道和片段的彩色强调线的颜色值。
2.13.Create Draw?属性:只有在没有选择Standard Blend Playable属性时才显示该属性。当选择该属性时,就会创建一个以Playable Name属性值作为开头,并且以Draw作为结尾的模板文件。该模板文件主要包含以下内容:
2.13.1.代替片段类型中行为类型对象上属性的绘制。
2.13.2.绘制的属性是由行为类型中非导出引用类型变量组成。

猜你喜欢

转载自blog.csdn.net/zjz520yy/article/details/118311585