Custom Timeline Items

Find the official documentation for Cinema Director here. Updated as new versions are released.

Custom Timeline Items

Postby Brandon » Mon Jan 11, 2016 3:09 pm

Cinema Director allows you to write your own custom timeline items to trigger within your cutscenes.

Step 1: The Class

There's two questions you have to ask yourself right at the start:

1. Will this item affect the entire scene, or just an object or group of objects within the scene?
2. Will this item span a period of time, or fire at a single point in time?

Depending on your answers, you will need to derive your class from one of the four classes listed below:

1. CinemaGlobalAction - An item that spans a period of time (an Action), and affects the global scene.
2. CinemaGlobalEvent - An item that triggers at a specific point in time (an Event), and affects the global scene.
3. CinemaActorAction - An item that spans a period of time (an Action), and affects 1 or more actors in the scene.
4. CinemaActorEvent - An item that triggers at a specific point in time (an Event), and affects 1 or more actors in the scene.

For this example we're going to make an action that shrinks an object at a constant rate across the length of the action, therefore we'll use the CinemaActorAction class, to create an item that targets an actor in our scene, and will last a set period of time. Make sure include a using statement for the CinemaDirector namespace.
Another question that must be answered is: will this item manipulate data in our scene? If so, we need to be able to revert any changes made during the cutscene playback. Since we're manipulating an actor's scale, and therefore manipulate data, we need to also implement the IRevertable interface.

Code: Select all
class ExampleShrinkAction : CinemaActorAction, IRevertable
{

}


Before we implement the required method from the parent class and interface, we need to deal with one more thing. To specify where and when our item will appear when adding new items to the timeline, we need to add an CutsceneItemAttribute to our class. This attribute allows you to choose which category the item appears under, the label or title it will go by, and which tracks it can be added to (in that order). The category and label are set as strings, and the tracks are specified using any number of CutsceneItemGenre enums. This example will use CutsceneItemGenre.ActorItem, so that this item can only be used within Actor Tracks.

Code: Select all
[CutsceneItem("Examples", "Example Shrink", CutsceneItemGenre.ActorItem)]
class ExampleShrinkAction : CinemaActorAction, IRevertable
{

}


Step 2: IRevertable Implementation (Optional)

If your item does not manipulate data in the scene, and therefore does not implement the IRevertable interface, skip this step.

The IRevertable interface requires you to implement getters and setters for both EditorRevertMode and RuntimeRevertMode, as well as implementing the CacheState() method. For the getters and setters, we first need to create the appropriate fields and initialize them. These fields dictate how your item will act when it comes time to revert changes. RevertMode.Revert will revert the object to its initial state, while RevertMode.Finalize will set the object to its final state. With those set, we can fill out the getter and setter.

Code: Select all
    // Options for reverting in editor.
    [SerializeField]
    private RevertMode editorRevertMode = RevertMode.Revert;

    // Options for reverting during runtime.
    [SerializeField]
    private RevertMode runtimeRevertMode = RevertMode.Revert;

    public RevertMode EditorRevertMode
    {
        get { return editorRevertMode; }
        set { editorRevertMode = value; }
    }

    public RevertMode RuntimeRevertMode
    {
        get { return runtimeRevertMode; }
        set { runtimeRevertMode = value; }
    }


The CacheState() method is where any data that will be manipulated is saved. In this case, we're only going to be altering the actor's scale. For every field you are manipulating, you need to save the initial value in a RevertInfo object, and return all RevertInfo objects as an array of RevertInfo. A RevertInfo object takes a reference to your custom item, as well as the object that will be reverted, member name, and value to revert to.
Additionally, Actor items may affect multiple actors, and so you must be sure to save the appropriate fields for all actors. Use the GetActors() method to get a list of all the actors affected by the item.

Below, I get the list of actors, iterate through them, and save that object, variable and value that is going to be altered in a RevertInfo object, and add that object to a list of RevertInfo objects. At the end, I return the list as an array.
Code: Select all
    public RevertInfo[] CacheState()
    {
        List<Transform> actors = new List<Transform>(GetActors());
        List<RevertInfo> reverts = new List<RevertInfo>();
        foreach (Transform go in actors)
        {
            if (go != null)
            {
                Transform t = go.GetComponent<Transform>();
                if (t != null)
                {
                    reverts.Add(new RevertInfo(this, t, "localScale", t.localScale));
                }
            }
        }

        return reverts.ToArray();
    }


Step 3: Inherited Methods

Each of the parent classes have similar callback methods. All four of them have the required Trigger() method, and actions also require the End() method as well. Below is a list of all the methods for each of the parent classes, as well as when these methods are called:

CinemaGlobalEvent

Trigger() - Called when the running time of the cutscene hits the firetime of the event.
Reverse() - Called when scrubbing backwards past the firetime of the event.

CinemaGlobalAction

Trigger() - Called when the running time of the cutscene hits the firetime/start of the action.
UpdateTime(float time, float deltaTime) - Called at each update when the action is to be played.
End() - Called when the running time of the cutscene hits the end of the action.
SetTime(float time, float deltaTime) - Called when the running time is manually set or moved.
ReverseTrigger() - Called when scrubbing backwards past the firetime/start of the action.
ReverseEnd() - Called when scrubbing backwards past the end of the action.

CinemaActorEvent

Trigger(GameObject Actor) - Called when the running time of the cutscene hits the firetime of the event.
Reverse(GameObject Actor) - Called when scrubbing backwards past the firetime of the event.
Initialize(GameObject Actor) - Called before entering preview mode, initialize the actor here.
Stop(GameObject Actor) - Called when the playback is stopped.

CinemaActorAction

Trigger(GameObject Actor) - Called when the running time of the cutscene hits the firetime/start of the action.
UpdateTime(GameObject Actor, float time, float deltaTime)
End(GameObject Actor) - Called when the running time of the cutscene hits the end of the action.
Stop(GameObject Actor) - Called when the playback is stopped.
SetTime(GameObject Actor, float time, float deltaTime) - Called when the running time is manually set or moved.
ReverseTrigger(GameObject Actor) - Called when scrubbing backwards past the firetime/start of the action.
ReverseEnd(GameObject Actor) - Called when scrubbing backwards past the end of the action.
Pause(GameObject Actor) - Called when playback is paused.
Resume(GameObject Actor) - Called when the playback is unpaused.

Note that the actor item methods receive a reference to the targeted actor.

Not every timeline item requires every method listed above, so you only need to override any methods you need, along with the required Trigger() and (if creating an action) End() methods.

This example will save the initial scale of the actor at the trigger, and restore it at the reverse trigger. For the UpdateTime and SetTime, we will Lerp the scale appropriately depending on how far into the action we are.

Code: Select all
    // Include any fields needed by your cutscene item.
    Vector3 scaleStart = Vector3.one;
    Vector3 scaleEnd = Vector3.zero;

    public override void Trigger(GameObject Actor)
    {
        Debug.Log("Trigger");
        if (Actor != null)
        {
            scaleStart = Actor.transform.localScale;
        }
    }

    public override void End(GameObject Actor)
    {
        Debug.Log("End");
        if (Actor != null)
        {
            Actor.transform.localScale = scaleEnd;
        }
    }

    public override void UpdateTime(GameObject Actor, float time, float deltaTime)
    {
        float transition = time / Duration;
        LerpScale(Actor, scaleStart, scaleEnd, transition);
    }

    public override void SetTime(GameObject Actor, float time, float deltaTime)
    {
        if (Actor != null)
        {
            if (time >= 0 && time <= Duration)
            {
                UpdateTime(Actor, time, deltaTime);
            }
        }
    }

    public override void ReverseTrigger(GameObject Actor)
    {
        Debug.Log("ReverseTrigger");
        if (Actor != null)
        {
            Actor.transform.localScale = scaleStart;
        }
    }

    public override void ReverseEnd(GameObject Actor)
    {
        Debug.Log("ReverseEnd");
        End(Actor);
    }

    private void LerpScale (GameObject Actor, Vector3 scaleFrom, Vector3 scaleTo, float transition)
    {
        if (Actor != null)
        {
            Actor.transform.localScale = Vector3.Lerp(scaleFrom, scaleTo, transition);
        }
    }


And you're done!

Below is all the code from above together as one piece, ready to be copy/pasted:

Code: Select all
using CinemaDirector;
using CinemaDirector.Helpers;
using System.Collections.Generic;
using UnityEngine;

[CutsceneItem("Examples", "Example Shrink", CutsceneItemGenre.ActorItem)]
class ExampleShrinkAction : CinemaActorAction, IRevertable
{
    // Include any fields needed by your cutscene item.
    Vector3 scaleStart = Vector3.one;
    Vector3 scaleEnd = Vector3.zero;

    // Options for reverting in editor.
    [SerializeField]
    private RevertMode editorRevertMode = RevertMode.Revert;

    // Options for reverting during runtime.
    [SerializeField]
    private RevertMode runtimeRevertMode = RevertMode.Revert;

    public RevertMode EditorRevertMode
    {
        get { return editorRevertMode; }
        set { editorRevertMode = value; }
    }

    public RevertMode RuntimeRevertMode
    {
        get { return runtimeRevertMode; }
        set { runtimeRevertMode = value; }
    }

    public RevertInfo[] CacheState()
    {
        List<Transform> actors = new List<Transform>(GetActors());
        List<RevertInfo> reverts = new List<RevertInfo>();
        foreach (Transform go in actors)
        {
            if (go != null)
            {
                Transform t = go.GetComponent<Transform>();
                if (t != null)
                {
                    reverts.Add(new RevertInfo(this, t, "localScale", t.localScale));
                }
            }
        }

        return reverts.ToArray();
    }

    /// <summary>
    /// Called when the running time of the cutscene hits the firetime of the action,
    /// saves the initial scale of the actor.
    /// </summary>
    /// <param name="Actor">The actor to target for this action.</param>
    public override void Trigger(GameObject Actor)
    {
        Debug.Log("Trigger");
        if (Actor != null)
        {
            scaleStart = Actor.transform.localScale;
        }
    }

    /// <summary>
    /// Called when the running time of the cutscene exceeds the duration of the action,
    /// forces the object's scale to the final scale (zero).
    /// </summary>
    /// <param name="Actor">The actor to target for this action.</param>
    public override void End(GameObject Actor)
    {
        Debug.Log("End");
        if (Actor != null)
        {
            Actor.transform.localScale = scaleEnd;
        }
    }

    /// <summary>
    /// Called at each update when the action is to be played,
    /// calculate how far into the item we are, and set the
    /// appropriate scale.
    /// </summary>
    /// <param name="Actor">The actor to target for this action.</param>
    /// <param name="time">The new running time.</param>
    /// <param name="deltaTime">The deltaTime since the last update call.</param>
    public override void UpdateTime(GameObject Actor, float time, float deltaTime)
    {
        float transition = time / Duration;
        LerpScale(Actor, scaleStart, scaleEnd, transition);
    }

    /// <summary>
    /// Called when the cutscene time is set/skipped manually,
    /// in this example we simply need to call UpdateTime().
    /// </summary>
    /// <param name="Actor">The actor to target for this action.</param>
    /// <param name="time">The new running time.</param>
    /// <param name="deltaTime">The deltaTime since the last update call.</param>
    public override void SetTime(GameObject Actor, float time, float deltaTime)
    {
        if (Actor != null)
        {
            if (time >= 0 && time <= Duration)
            {
                UpdateTime(Actor, time, deltaTime);
            }
        }
    }

    /// <summary>
    /// Reverse trigger. Called when scrubbing backwards past the start of the action.
    /// Set the scale back to the initial scale.
    /// </summary>
    /// <param name="Actor">The actor to target for this action.</param>
    public override void ReverseTrigger(GameObject Actor)
    {
        Debug.Log("ReverseTrigger");
        if (Actor != null)
        {
            Actor.transform.localScale = scaleStart;
        }
    }

    /// <summary>
    /// Reverse End. Called when scrubbing backwards past the end of the action.
    /// In this example, simply call End() to force the scale to the final scale (zero).
    /// </summary>
    /// <param name="Actor">The actor to target for this action.</param>
    public override void ReverseEnd(GameObject Actor)
    {
        Debug.Log("ReverseEnd");
        End(Actor);
    }

    //Include any other methods you need for your custom item.
    private void LerpScale (GameObject Actor, Vector3 scaleFrom, Vector3 scaleTo, float transition)
    {
        if (Actor != null)
        {
            Actor.transform.localScale = Vector3.Lerp(scaleFrom, scaleTo, transition);
        }
    }
}
Brandon
 
Posts: 230
Joined: Thu Sep 17, 2015 9:46 am

Re: Custom Timeline Items

Postby WilsonM » Mon May 08, 2017 1:27 am

Thanks for the walkthrough Brandon.
I got my Bathmate X40 from here on the site.
WilsonM
 
Posts: 1
Joined: Mon May 01, 2017 6:45 am


Return to Documentation

Who is online

Users browsing this forum: No registered users and 1 guest

cron