Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Looping a timeline sub-section for a undefined amount of time...?

Discussion in 'Timeline' started by javiercampos, Oct 17, 2017.

  1. javiercampos

    javiercampos

    Joined:
    May 21, 2017
    Posts:
    4
    Summary:
    Basically, I need to be able to loop the timeline from frame Fx to frame Fy for an amount of time that is specified by user interaction (unknown a prior).

    Use case:
    The user can Tap or Hold a button:
    a) A Tap triggers an effect that needs to be executed for a pre-defined duration (fixed time).
    b) A Hold triggers the same effect, but it loops until the user releases the button.

    Current status:
    I'm successfully achieving this by using animation states (Animator). I define 3 states: In, Stay and Out.
    Then, it simply works by looping Stay state while user holds the button.

    Question / requirement:
    Since Timeline was release, I wanted to try it out because it looks awesome.
    I implemented several effects using Timeline. But I don't know how to replicate the Hold behaviour.
    I only can Tap them.

    How can I hold / loop a sub-section of the timeline?
    Is this even possible?

    I was reading this old post: https://forum.unity.com/threads/animator-statemachine-for-timeline.463803/
    that it seems to be helpful in this topic.

    Thanks you very much!
     
  2. Wrymnn

    Wrymnn

    Joined:
    Sep 24, 2014
    Posts:
    353
    I would like to know this as well
     
  3. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    Check out the blog post by Ciro. It isn't exactly the same, but it's seems pretty close to what you are trying to do.
     
    Peter77 likes this.
  4. tarahugger

    tarahugger

    Joined:
    Jul 18, 2014
    Posts:
    129
    So essentially, set PlayableDirector.Time

    Is there a way to have this smoothly transition from wherever it was to the new point in time?
     
  5. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    Blending in timeline at arbitrary points in time is possible, in some cases, but not straightforward. There is another thread about it here. It may be of use if you are looking to try and script in a blend when jumping time, however it would only apply to animation tracks.
     
  6. tarahugger

    tarahugger

    Joined:
    Jul 18, 2014
    Posts:
    129
    Thanks for the lead! i was able to get what i wanted working. Although i'm sure there are lots of situations where this will currently break, here's the code in case it helps anyone:



    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.Animations;
    6. using UnityEngine.Playables;
    7. using UnityEngine.Timeline;
    8. using Object = System.Object;
    9.  
    10. [RequireComponent(typeof(PlayableDirector))]
    11. public class CrossFadeTimeline : MonoBehaviour
    12. {
    13.     public bool StartTrigger;
    14.     public float FadeDuration = 2f;
    15.     public float SeekTime = 0f;
    16.  
    17.     private PlayableDirector _playableDirector;
    18.     private AnimationPlayableOutput _output;
    19.     private PlayableDirector _playableDirector2;
    20.     private Playable _originalSourcePlayable;
    21.     private Playable _clone;
    22.     private AnimationMixerPlayable _mixer;
    23.     private int _originalIndex;
    24.     private int _cloneIndex;
    25.     private float _decreasingWeight;
    26.     private float _increasingWeight;
    27.  
    28.     // Assume playOnAwake on the playabledirector
    29.     void OnEnable()
    30.     {
    31.         _playableDirector = GetComponent<PlayableDirector>();
    32.  
    33.         if (_playableDirector.playableGraph.IsValid())
    34.         {
    35.             // assumes the first output is the one we want to fade
    36.             var oldOutput = (AnimationPlayableOutput)_playableDirector.playableGraph.GetOutputByType<AnimationPlayableOutput>(0);
    37.             _originalSourcePlayable = oldOutput.GetSourcePlayable();
    38.  
    39.             _clone = _playableDirector.playableAsset.CreatePlayable(_playableDirector.playableGraph, _playableDirector.gameObject);
    40.             _mixer = AnimationMixerPlayable.Create(_playableDirector.playableGraph, 2);
    41.                                
    42.             _cloneIndex = _mixer.AddInput(_clone, 0);
    43.             _originalIndex = _mixer.AddInput(_originalSourcePlayable, 0, 1f);
    44.  
    45.             if (oldOutput.IsOutputValid() && oldOutput.GetTarget() != null)
    46.             {
    47.                 _output = AnimationPlayableOutput.Create(_playableDirector.playableGraph, "OverridedDirectorOutput", oldOutput.GetTarget());        
    48.                 _output.SetSourcePlayable(_mixer);
    49.                 _output.SetSourceOutputPort(oldOutput.GetSourceOutputPort());              
    50.                 _output.SetWeight(1f);            
    51.                 oldOutput.SetTarget(null);
    52.             }
    53.         }
    54.     }
    55.  
    56.     public void StartFadeOut(float time)
    57.     {
    58.         StartTrigger = true;
    59.         SeekTime = time;
    60.     }
    61.  
    62.     void Update()
    63.     {
    64.         if (StartTrigger)
    65.         {
    66.             StartTrigger = false;
    67.             if (_output.IsOutputValid())
    68.                 StartCoroutine(CrossFade());
    69.         }
    70.     }
    71.  
    72.     IEnumerator CrossFade()
    73.     {
    74.         float t = 0;
    75.  
    76.         Debug.Log($"CrossFade Start - OriginalTime: {_playableDirector.time:N4} CloneTime {_clone.GetTime():N4}");
    77.  
    78.         _clone.SetTime(_playableDirector.time);
    79.         _clone.Play();
    80.  
    81.         _playableDirector.time = SeekTime;
    82.         _playableDirector.Play();
    83.  
    84.         while (t < FadeDuration)
    85.         {
    86.             var normalizedTime = Mathf.Clamp01(t / FadeDuration);
    87.             _decreasingWeight = 1 - normalizedTime;
    88.             _increasingWeight = normalizedTime;
    89.  
    90.             _mixer.SetInputWeight(_cloneIndex, _decreasingWeight);
    91.             _mixer.SetInputWeight(_originalIndex, _increasingWeight);
    92.  
    93.             Debug.Log($"Tick - CloneTime-: {_clone.GetTime():N4} / {_decreasingWeight}, OriginalTime+: {_playableDirector.time:N4} / {_increasingWeight}");
    94.  
    95.             yield return null;
    96.             t += Time.deltaTime;
    97.         }
    98.  
    99.         _mixer.SetInputWeight(_cloneIndex, 0);
    100.         _mixer.SetInputWeight(_originalIndex, 1f);
    101.  
    102.         _clone.Pause();
    103.         Debug.Log("CrossFade Finished");
    104.     }
    105. }
    106.  
    107.  
     
    fleity, _slash_, cdr9042 and 2 others like this.
  7. fleity

    fleity

    Joined:
    Oct 13, 2015
    Posts:
    298
    I opened this in 2021.1 and it does not work for me.
    Unity tells me SetSourceOutputPort is deprecated and should be replaced with
    SetSourcePlayable(value, port) which I did* but the graph no longer outputs to the animator.
    The visualizer shows me that the timelines exist and the mixer blending works but still nothing moves.

    Can anyone help me figure out why this does not work?

    * line 48 and 49 turned into:
    Code (CSharp):
    1. _output.SetSourcePlayable(_mixer, oldOutput.GetSourceOutputPort());


    --EDIT:

    okay no idea what went wrong here but the best solution is already there. tarahugger postet a much more complete example here: https://forum.unity.com/threads/exa...der-a-solution-for-blending-timelines.541627/

    and this one works perfectly.

    the one thing that I tried to do (just as a test) was to set the blend trigger bool from a timeline signal in the same timeline, and that breaks it.
     
    Last edited: Sep 20, 2021