4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Unity】Timelineの再生位置をスライダーで指定する

Last updated at Posted at 2020-01-18

こんにちはっ🌟八ツ橋まろんですっ!

ARアプリを作っているときに、Timelineをスライダーで操作したくなったのでスクリプトを書きました。本記事ではそのコードと解説をします。

↓↓↓↓このコードによってこんなことができます↓↓↓↓(GIF)
(このGIFではアニメーションだけが入ったTimelineを使用しています)
Qiita.gif

・再生ボタン/一時停止ボタンの実装
・Timelineの進行度合いがスライダーに反映される
・スライダーの位置をクリックして変えるとTimelineの再生位置も連動する

以下、完成コード

TimelineUiController.cs
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Playables;
using System; // Actionに必要

public class TimelineUiController : MonoBehaviour
{
    [SerializeField]
    PlayableDirector timeline;

    [SerializeField]
    Slider slider;

    [SerializeField]
    GameObject playButton;

    [SerializeField]
    GameObject pauseButton;

    double length;

    float sliderValue;
    float sliderValueStored;
    float time;

    private void Start()
    {
        length = timeline.duration;
        Play();
    }

    void Update()
    {
        sliderValue = slider.value;
        time = ConvertDtoF(timeline.time);

        if(time >= 0.995 && timeline.extrapolationMode != DirectorWrapMode.Loop)
        {
            playButton.SetActive(true);
            pauseButton.SetActive(false);
        }

        if (sliderValue != sliderValueStored)
        {
            sliderValueStored = sliderValue;
            time = sliderValue;
            SetTimelineTime(time);
        }
        else if(time != sliderValueStored)
        {
            slider.value = time;
            sliderValueStored = time;
        }
    }

    public void Play()
    {
        timeline.Play();
        playButton.SetActive(false);
        pauseButton.SetActive(true);
    }

    public void Stop()
    {
        timeline.Stop();
        PlayOneFrame();
    }

    public void Pause()
    {
        timeline.Pause();

        time = ConvertDtoF(timeline.time);
        sliderValue = time;
        sliderValueStored = time;
        playButton.SetActive(true);
        pauseButton.SetActive(false);
    }
    public void LengthReset()
    {
        length = timeline.duration;
    }
    void PlayOneFrame()
    {
        Play();

        //1フレーム後にPauseする
        StartCoroutine(DelayMethod(1, () => {Pause(); }));
    }

    private IEnumerator DelayMethod(int delayFrameCount, Action action)
    {
        for (var i = 0; i < delayFrameCount; i++)
        {
            yield return null;
        }
        action();
    }

    void SetTimelineTime(float f)
    {
        double d = ConvertFtoD(f);
        timeline.time = d;
        PlayOneFrame();
    }

    double ConvertFtoD(float f)
    {
        double d = (double)(f * length);
        return d;
    }

    float ConvertDtoF(double d)
    {
        float f = (float)d / (float)length;
        return f;
    }
}


###使い方
[SerializeField]
PlayableDirector timeline;

[SerializeField]
Slider slider;

[SerializeField]
GameObject playButton;

[SerializeField]
GameObject pauseButton;

上記にPlayableDirectorとスライダー、再生ボタン、停止ボタンをあてがってください。

###解説
Timelineの総時間は

length = timeline.duration;

で取得できます。ただし、これはdouble型で得られるため、スライダーと連動したいならfloat型に変換しないといけないので注意。

float ConvertDtoF(double d)
{
    float f = (float)d / (float)length;
    return f;
}

timeline.timeで現在の再生位置をdouble型で取得し、総時間で割ったあとにfloat型に変換して、0~1にしています。

time = ConvertDtoF(timeline.time);

スライダーを触ってtimelineの再生位置を変更する場合、timeline.Pause();してtimeline.time = xxx;だけではスライダー位置が動かないため、その後に1フレームだけ再生することでスライダー位置を動かすようにしています。

###おわりに
Timelineの再生位置制御の需要は、なかなかないと思いますが、Animation制御を越えてカメラワークやエフェクトの巻き戻しとかを任意でやりたい場合に使えます✨よかったら使ってみてください。

八ツ橋まろん

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?