[Unity] Timeline exploration: the second example -- action close-up / bullet time

Write in front

  • Refer to this article for this example Implementation blog (download attached items). The previous introduction of the blog post is very specific. Unfortunately, the close-up track implementation code behind is not organized according to the four standard pieces (data, mixer, clip and track) I want, so I skip the introduction here and only record the problems I encounter in the implementation.
  • Test environment unity2019 2.6: because the mobile lens is used Cinemachine plug-in The plug-in needs to be installed with Package above Unity2018 (previously Cinemachine was placed in the Asset Store, but now it has been removed from the shelf), and Unity2017 also needs to be installed The latest Cinemachine is not supported Therefore, unity 2019 is used here 2.6 to test.
  • Because the focus of the implementation is "action close-up", rather than studying Cinemachine, I didn't go deep into Cinemachine here.

Record

  • After creating a virtual camera with Cinemachine plug-in, the main camera needs to move the position by using the Virtual Camera/vcam. Moreover, if vcam wants to change the position (position + angle), it can only be adjusted manually in the scene, not directly.
  • [question 1] when testing the "action close-up", the center of vcam looking at the target is very low (see the figure below), but the reference is very appropriate (see the figure below). What's the matter?

My test: the center (yellow line) is very low

Reference: the position (at the yellow line) made by others is very suitable

- > targetgroup cannot be moved. However, in my test, the target is the foot of the character (see the left figure below), while the target of the reference is the waist of the character (see the right figure below), so the center is inconsistent.

                    

  • [question 2] after adding the action, the character does the action in place instead of running towards the enemy. How can he run towards the enemy? - > The solution is to join the override track and record the person's position on the override track.
    • If the override track is mute, you will not see the effect when editing
    • For the blank override track, click record first, add a key frame randomly, and then double-click the override track to edit the effect
    • I thought about using MatchOffsets to change the action, but this function is used for the smooth transition between two actions, and the character has to run to the enemy. The displacement between them is too large to be completed with MatchOffsets.
  • [question 3] the characters have rising and idle movements, which are not well integrated and have displacement - > the solution is the same as above.
  • Reference blog The Animation Curve is used to change the Time and realize the user-defined close-up track, but it is not organized according to the standard four pieces of data, mixer, clip and track. It only writes a script, and also covers the reference track Playable Track exposed by Unity. I named the close-up track Time and reorganized the code according to the four standard pieces, as follows:
    • data: TimeBehaviour.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;


[Serializable]
public class TimeBehaviour : PlayableBehaviour
{
    public AnimationCurve curve;

}
    • mixer: TimeMixerBehaviour.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;

public class TimeMixerBehaviour : PlayableBehaviour
{
    private float curTime = 0;
    private float maxTime = 0;

    public override void OnGraphStart(Playable playable)
    {

    }

    public override void OnGraphStop(Playable playable)
    {
        Time.timeScale = 1;
    }

    public override void OnBehaviourPlay(Playable playable, FrameData info)
    {

    }

    public override void OnBehaviourPause(Playable playable, FrameData info)
    {

    }

    public override void PrepareFrame(Playable playable, FrameData info)
    {

    }

    public override void ProcessFrame(Playable playable, FrameData info, object playerData)
    {
        float scale = 1;
        int inputCount = playable.GetInputCount();
        for (int i = 0; i < inputCount; i++)
        {
            float inputWeight = playable.GetInputWeight(i);
            if (!Mathf.Approximately(inputWeight, 0f))
            {
                curTime += info.deltaTime;
                ScriptPlayable<TimeBehaviour> inputPlayable = (ScriptPlayable<TimeBehaviour>)playable.GetInput(i);
                TimeBehaviour input = inputPlayable.GetBehaviour();
                // maxTime current clip Duration of
                maxTime = (float)PlayableExtensions.GetDuration(playable.GetInput(i));
                // curTime current clip When is the execution of the
                scale = input.curve.Evaluate(curTime / maxTime);
            }
            else
            {
                curTime = 0;
            }
        }
        Time.timeScale = scale;

    }

}
    • clip: TimeClip.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;

[System.Serializable]
public class TimeClip : PlayableAsset, ITimelineClipAsset
{
    public TimeBehaviour template = new TimeBehaviour();

    public ClipCaps clipCaps
    {
        get
        {
            return ClipCaps.Blending; //choice None,clip Of course, the shortcut key fade in and fade out operation is not supported
        }
    }

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

    }

}
    • track: TimeTrack.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
using UnityEngine.UI;

[TrackColor(0.898f, 0.701f, 0.207f)]
[TrackClipType(typeof(TimeClip))]
[System.Serializable]
public class TimeTrack : TrackAsset
{
    public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
    {
        return ScriptPlayable<TimeMixerBehaviour>.Create(graph, inputCount);

    }

    public override void GatherProperties(PlayableDirector director, IPropertyCollector driver)
    {
        base.GatherProperties(director, driver);

    }
}
  • Compared with the reference code of the blog, my code modification focuses on:
    • [key point 1] as shown in the following figure, maxTime in the blog post: because the mixer script is not used, maxTime can directly get the duration of the current clip;

maxTime of Blog

The mixer script I wrote is shown in the figure below. maxTime should be valued like this. If you write like a blog post, the maxTime you get will be endless.

I wrote maxTime

    • [Key 2] as shown in the figure below, curTime in this blog post will get the progress time of the current clip, which means that when there is no clip or switching to the next clip, curTime will become 0;

curTime of Blog

The curTime I wrote is shown in the figure below. It should be taken like this to get the progress time of the current clip.

 

Tags: Unity

Posted by crash58 on Sat, 14 May 2022 04:48:37 +0300