Version: Unity 6.0 (6000.0)
언어 : 한국어
ScriptPlayable 및 PlayableBehaviour
성능 및 최적화

플레이어블 예시

플레이어블 그래프 비주얼라이저

이 페이지의 예시는 플레이어블 그래프 비주얼라이저를 사용하여 플레이어블 API로 생성된 나무와 노드를 나타냅니다. 플레이어블 그래프 비주얼라이저는 GitHub를 통해 사용할 수 있는 툴입니다.

참고: 플레이어블 그래프 비주얼라이저는 현재 사용 중인 Unity 버전에서 작동하지 않을 수 있는 지원 중단된 실험용 패키지입니다.

플레이어블 그래프 비주얼라이저를 사용하는 방법은 다음과 같습니다.

  1. GitHub 저장소에서 플레이어블 그래프 비주얼라이저를 다운로드합니다.

  2. Window > PlayableGraph Visualizer를 선택하여 도구를 엽니다.

  3. GraphVisualizerClient.Show(PlayableGraph graph, string name)를 사용하여 그래프를 등록합니다.

GraphVisualizer 창
GraphVisualizer 창

그래프의 플레이어블은 컬러가 지정된 노드로 표시됩니다. 와이어 컬러 강도는 블렌드 가중치를 의미합니다. 플레이어블 그래프 비주얼라이저에 대한 자세한 내용은 GitHub를 참조하십시오.

게임 오브젝트의 단일 애니메이션 클립 재생

이 예시는 단일 플레이어블 노드에 연결된 단일 플레이어블 출력으로 단순한 PlayableGraph를 보여 줍니다. 플레이어블 노드는 단일 애니메이션 클립(클립)을 재생합니다. 애니메이션 클립을 Playables API와 호환하려면 AnimationClipPlayable이 애니메이션 클립을 래핑해야 합니다.

using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;

[RequireComponent(typeof(Animator))]
public class PlayAnimationSample : MonoBehaviour
{
    public AnimationClip clip;
    PlayableGraph playableGraph;

    void Start()
    {
        playableGraph = PlayableGraph.Create();
        playableGraph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);

        var playableOutput = AnimationPlayableOutput.Create(playableGraph, "Animation", GetComponent<Animator>());

        // Wrap the clip in a playable.
        var clipPlayable = AnimationClipPlayable.Create(playableGraph, clip);

        // Connect the Playable to an output.
        playableOutput.SetSourcePlayable(clipPlayable);

        // Plays the Graph.
        playableGraph.Play();
    }

    void OnDisable()
    {
        // Destroys all Playables and PlayableOutputs created by the graph.
        playableGraph.Destroy();
    }
}
PlayAnimationSample에 의해 생성된 플레이어블 그래프
PlayAnimationSample에 의해 생성된 플레이어블 그래프

아래 예시와 같이 AnimationPlayableUtilities를 사용하여 애니메이션 플레이어블의 생성과 재생을 간소화할 수 있습니다.

using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;

[RequireComponent(typeof(Animator))]
public class PlayAnimationUtilitiesSample : MonoBehaviour
{

    public AnimationClip clip;
    PlayableGraph playableGraph;

    void Start()
    {
        AnimationPlayableUtilities.PlayClip(GetComponent<Animator>(), clip, out playableGraph);
    }

    void OnDisable()
    {
        // Destroys all Playables and Outputs created by the graph.
        playableGraph.Destroy();
    }
}

애니메이션 블렌드 트리 생성

이 예시는 AnimationMixerPlayable을 사용하여 두 애니메이션 클립을 블렌딩하는 방법을 보여 줍니다. 애니메이션 클립을 블렌딩하기 전에 플레이어블로 래핑해야 합니다. 이를 위해 AnimationClipPlayable(clipPlayable0 및 clipPlayable1)은 각 AnimationClip(clip0 및 clip1)을 래핑합니다. SetInputWeight() 메서드는 각 플레이어블의 블렌드 가중치를 동적으로 조정합니다.

아래 예시에 나와 있지는 않지만, AnimationMixerPlayable을 사용하여 플레이어블 믹서와 기타 플레이어블을 블렌드할 수도 있습니다.

using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;

[RequireComponent(typeof(Animator))]
public class MixAnimationSample : MonoBehaviour
{

    public AnimationClip clip0;
    public AnimationClip clip1;
    public float weight;
    PlayableGraph playableGraph;
    AnimationMixerPlayable mixerPlayable;

    void Start()
    {
        // Creates the graph, the mixer and binds them to the Animator.
        playableGraph = PlayableGraph.Create();

        var playableOutput = AnimationPlayableOutput.Create(playableGraph, "Animation", GetComponent<Animator>());

        mixerPlayable = AnimationMixerPlayable.Create(playableGraph, 2);
        playableOutput.SetSourcePlayable(mixerPlayable);

        // Creates AnimationClipPlayable and connects them to the mixer.
        var clipPlayable0 = AnimationClipPlayable.Create(playableGraph, clip0);
        var clipPlayable1 = AnimationClipPlayable.Create(playableGraph, clip1);

        playableGraph.Connect(clipPlayable0, 0, mixerPlayable, 0);
        playableGraph.Connect(clipPlayable1, 0, mixerPlayable, 1);

        // Plays the Graph.
        playableGraph.Play();
    }

    void Update()
    {
        weight = Mathf.Clamp01(weight);
        mixerPlayable.SetInputWeight(0, 1.0f-weight);
        mixerPlayable.SetInputWeight(1, weight);
    }

    void OnDisable()
    {
        // Destroys all Playables and Outputs created by the graph.
        playableGraph.Destroy();
    }
}
`MixAnimationSample에 의해 생성된 PlayableGraph
`MixAnimationSample에 의해 생성된 PlayableGraph

AnimationClip과 AnimatorController 블렌드

이 예시는 AnimationMixerPlayable을 사용하여 AnimationClipAnimatorController를 혼합하는 방법을 보여 줍니다.

AnimationClipAnimatorController를 혼합하기 전에 플레이어블로 래핑해야 합니다. 이를 위해 AnimationClipPlayable(clipPlayable)은 AnimationClip(클립)을 래핑하고 AnimatorControllerPlayable(ctrlPlayable)은 RuntimeAnimatorController(컨트롤러)를 래핑합니다. SetInputWeight() 메서드는 각 플레이어블의 블렌드 가중치를 동적으로 조정합니다.

using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;

[RequireComponent(typeof(Animator))]
public class RuntimeControllerSample : MonoBehaviour
{
    public AnimationClip clip;
    public RuntimeAnimatorController controller;
    public float weight;

    PlayableGraph playableGraph;
    AnimationMixerPlayable mixerPlayable;

    void Start()
    {
        // Creates the graph, the mixer and binds them to the Animator.
        playableGraph = PlayableGraph.Create();

        var playableOutput = AnimationPlayableOutput.Create(playableGraph, "Animation", GetComponent<Animator>());
        mixerPlayable = AnimationMixerPlayable.Create(playableGraph, 2);
        playableOutput.SetSourcePlayable(mixerPlayable);

        // Creates AnimationClipPlayable and connects them to the mixer.
        var clipPlayable = AnimationClipPlayable.Create(playableGraph, clip);
        var ctrlPlayable = AnimatorControllerPlayable.Create(playableGraph, controller);

        playableGraph.Connect(clipPlayable, 0, mixerPlayable, 0);
        playableGraph.Connect(ctrlPlayable, 0, mixerPlayable, 1);

        // Plays the Graph.
        playableGraph.Play();
    }

    void Update()
    {
        weight = Mathf.Clamp01(weight);
        mixerPlayable.SetInputWeight(0, 1.0f-weight);
        mixerPlayable.SetInputWeight(1, weight);
    }

    void OnDisable()
    {
        // Destroys all Playables and Outputs created by the graph.
        playableGraph.Destroy();
    }
}

여러 출력이 있는 플레이어블 그래프 생성

이 예시는 두 가지 플레이어블 출력 유형(AudioPlayableOutputAnimationPlayableOutput)으로 PlayableGraph를 만드는 방법을 보여 줍니다. PlayableGraph는 다양한 유형의 여러 플레이어블 출력을 가질 수 있습니다.

이 예시는 또한 AudioPlayableOutput에 연결된 AudioClipPlayable을 통해 AudioClip을 재생하는 방법을 보여 줍니다.

using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Audio;
using UnityEngine.Playables;

[RequireComponent(typeof(Animator))]
[RequireComponent(typeof(AudioSource))]
public class MultiOutputSample : MonoBehaviour
{
    public AnimationClip animationClip;
    public AudioClip audioClip;
    PlayableGraph playableGraph;

    void Start()
    {
        playableGraph = PlayableGraph.Create();

        // Create the outputs.
        var animationOutput = AnimationPlayableOutput.Create(playableGraph, "Animation", GetComponent<Animator>());

        var audioOutput = AudioPlayableOutput.Create(playableGraph, "Audio", GetComponent<AudioSource>());

        // Create the playables.
        var animationClipPlayable = AnimationClipPlayable.Create(playableGraph, animationClip);
        var audioClipPlayable = AudioClipPlayable.Create(playableGraph, audioClip, true);

        // Connect the playables to an output.
        animationOutput.SetSourcePlayable(animationClipPlayable);
        audioOutput.SetSourcePlayable(audioClipPlayable);

        // Plays the Graph.
        playableGraph.Play();
    }

    void OnDisable()
    {
        // Destroys all Playables and Outputs created by the graph.
        playableGraph.Destroy();
    }
}
`MultiOutputSample에 의해 생성된 PlayableGraph
`MultiOutputSample에 의해 생성된 PlayableGraph

트리의 재생 상태 제어

이 예시는 PlayableGraph 트리의 노드 재생 상태를 제어하는 방법을 보여 줍니다. Pause()Play() 메서드는 나무 전체, 그 가지 중 하나 또는 단일 노드의 재생 상태를 제어합니다.

노드의 재생 상태를 설정하면 재생 상태와 관계없이 해당 상태가 모든 자식에게 전파됩니다. 예를 들어 자식 노드가 명시적으로 일시 정지된 경우 부모 노드를 재생으로 설정하면 해당 자식 노드도 재생으로 설정됩니다.

이 예시에서 PlayableGraph에는 두 개의 애니메이션 클립을 블렌딩하는 믹서가 포함되어 있습니다. AnimationClipPlayable은 각 애니메이션 클립을 래핑하고, Pause() 메서드는 두 번째 플레이어블을 명시적으로 일시 정지시킵니다. 두 번째 AnimationClipPlayable이 명시적으로 일시 정지되므로 내부 시간이 진행되지 않고 동일한 값을 출력합니다. 정확한 값은 AnimationClipPlayable이 일시 정지된 특정 시간에 따라 달라집니다.

using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;

[RequireComponent(typeof(Animator))]
public class PauseSubGraphAnimationSample : MonoBehaviour
{
    public AnimationClip clip0;
    public AnimationClip clip1;

    PlayableGraph playableGraph;
    AnimationMixerPlayable mixerPlayable;

    void Start()
    {
        // Creates the graph, the mixer and binds them to the Animator.

        playableGraph = PlayableGraph.Create();

        var playableOutput = AnimationPlayableOutput.Create(playableGraph, "Animation", GetComponent<Animator>());

        mixerPlayable = AnimationMixerPlayable.Create(playableGraph, 2);
        playableOutput.SetSourcePlayable(mixerPlayable);

        // Creates AnimationClipPlayable and connects them to the mixer.

        var clipPlayable0 = AnimationClipPlayable.Create(playableGraph, clip0);
        var clipPlayable1 = AnimationClipPlayable.Create(playableGraph, clip1);

        playableGraph.Connect(clipPlayable0, 0, mixerPlayable, 0);
        playableGraph.Connect(clipPlayable1, 0, mixerPlayable, 1);
        mixerPlayable.SetInputWeight(0, 1.0f);
        mixerPlayable.SetInputWeight(1, 1.0f);
        clipPlayable1.Pause();

        // Plays the Graph.
        playableGraph.Play();
    }

    void OnDisable()
    {
        // Destroys all Playables and Outputs created by the graph.
        playableGraph.Destroy();
    }
}
PauseSubGraphAnimationSample에 의해 생성된 플레이어블 그래프. 두 번째 클립(빨간색 테두리)이 일시 정지되었음을 알 수 있습니다.
PauseSubGraphAnimationSample에 의해 생성된 플레이어블 그래프. 두 번째 클립(빨간색 테두리)이 일시 정지되었음을 알 수 있습니다.

나무의 타이밍 제어

다음은 Play() 메서드를 사용하여 플레이어블 그래프를 재생하고, Pause() 메서드를 사용하여 플레이어블을 일시 정지하고, SetTime() 메서드를 사용하여 변수를 통해 플레이어블의 로컬 시간을 수동으로 설정하는 방법을 보여 주는 예시입니다.

using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;

[RequireComponent(typeof(Animator))]
public class PlayWithTimeControlSample : MonoBehaviour
{
    public AnimationClip clip;
    public float time;
    PlayableGraph playableGraph;
    AnimationClipPlayable playableClip;

    void Start()
    {
        playableGraph = PlayableGraph.Create();
        var playableOutput = AnimationPlayableOutput.Create(playableGraph, "Animation", GetComponent<Animator>());

        // Wrap the clip in a playable.
        playableClip = AnimationClipPlayable.Create(playableGraph, clip);

        // Connect the Playable to an output.
        playableOutput.SetSourcePlayable(playableClip);

        // Plays the Graph.
        playableGraph.Play();

        // Stops time from progressing automatically.
        playableClip.Pause();
    }

    void Update ()
    {
        // Control the time manually.
        playableClip.SetTime(time);
    }

    void OnDisable()
    {
        // Destroys all Playables and Outputs created by the graph.
        playableGraph.Destroy();
    }
}

PlayableBehaviour 생성

이 예시는 PlayableBehaviour public 클래스를 사용하여 커스텀 플레이어블을 생성하는 방법을 보여 줍니다. 이 예시에서는 PrepareFrame() 가상 메서드를 오버라이드하여 PlayableGraph의 노드를 제어하는 방법도 보여 줍니다. 커스텀 플레이어블은 PlayableBehaviour 클래스의 다른 모든 가상 메서드를 오버라이드할 수 있습니다.

이 예시에서 제어되고 있는 노드는 일련의 애니메이션 클립(clipsToPlay)입니다. SetInputMethod()는 각 애니메이션 클립의 블렌드 가중치를 수정하여 클립이 한 번에 하나씩만 재생되도록 하고, SetTime() 메서드는 로컬 시간을 조정하여 애니메이션 클립이 활성화되는 순간에 재생이 시작되도록 합니다.

using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;

public class PlayQueuePlayable : PlayableBehaviour
{
    private int m_CurrentClipIndex = -1;
    private float m_TimeToNextClip;
    private Playable mixer;

    public void Initialize(AnimationClip[] clipsToPlay, Playable owner, PlayableGraph graph)
    {
        owner.SetInputCount(1);
        mixer = AnimationMixerPlayable.Create(graph, clipsToPlay.Length);
        graph.Connect(mixer, 0, owner, 0);
        owner.SetInputWeight(0, 1);

        for (int clipIndex = 0 ; clipIndex < mixer.GetInputCount() ; ++clipIndex)
        {
            graph.Connect(AnimationClipPlayable.Create(graph, clipsToPlay[clipIndex]), 0, mixer, clipIndex);
            mixer.SetInputWeight(clipIndex, 1.0f);
        }
    }

    override public void PrepareFrame(Playable owner, FrameData info)
    {
        if (mixer.GetInputCount() == 0)
            return;

        // Advance to next clip if necessary.
        m_TimeToNextClip -= (float)info.deltaTime;

        if (m_TimeToNextClip <= 0.0f)
        {
            m_CurrentClipIndex++;
            if (m_CurrentClipIndex >= mixer.GetInputCount())
                m_CurrentClipIndex = 0;
            var currentClip = (AnimationClipPlayable)mixer.GetInput(m_CurrentClipIndex);

            // Reset the time so that the next clip starts at the correct position.
            currentClip.SetTime(0);

            m_TimeToNextClip = currentClip.GetAnimationClip().length;
        }

        // Adjust the weight of the inputs.
        for (int clipIndex = 0 ; clipIndex < mixer.GetInputCount(); ++clipIndex)
        {
            if (clipIndex == m_CurrentClipIndex)
                mixer.SetInputWeight(clipIndex, 1.0f);
            else
                mixer.SetInputWeight(clipIndex, 0.0f);
        }
    }
}

[RequireComponent(typeof (Animator))]
public class PlayQueueSample : MonoBehaviour
{
    public AnimationClip[] clipsToPlay;
    PlayableGraph playableGraph;

    void Start()
    {
        playableGraph = PlayableGraph.Create();
        var playQueuePlayable = ScriptPlayable<PlayQueuePlayable>.Create(playableGraph);
        var playQueue = playQueuePlayable.GetBehaviour();

        playQueue.Initialize(clipsToPlay, playQueuePlayable, playableGraph);

        var playableOutput = AnimationPlayableOutput.Create(playableGraph, "Animation", GetComponent<Animator>());

        playableOutput.SetSourcePlayable(playQueuePlayable);
        playableOutput.SetSourceInputPort(0);
        playableGraph.Play();
    }

    void OnDisable()
    {
        // Destroys all Playables and Outputs created by the graph.
        playableGraph.Destroy();
    }
}
PlayQueueSample에 의해 생성된 플레이어블 그래프
PlayQueueSample에 의해 생성된 플레이어블 그래프

ScriptPlayable 및 PlayableBehaviour
성능 및 최적화