Time.timeScale = 0f; 형태로 구현한 일시정지 기능에서의 UI 애니메이터 동작 하지 않는 문제 해결 방법.

 

처음에 전체 게임의 일시정지 기능을 구현할때 Time.timeScale = 0f; 가 되도록 구현하였는데, 

이렇게 할시에 일시정지 팝업을 띄울때 팝업이 처음 애니메이션에서 사이즈가 0으로 시작해서 1이 되도록 커지는 형태로 설정시 그대로 0인 상태로 팝업 프리팹의 클론만 생성되고 화면에 보이지 않는 문제가 발생해서 문제가 무엇일가 생각해보니 타임스케일이 0이 되어버리면서 애니메이션이 동작하지 않는다는것을 알게 되어서 해당 문제에 대한 해결 방법을 알아보게 되었다. 

 

이때에 Animator 컴포넌트의 Update Mode 에서 Unscaled Time 을 선택하면 해당 문제를 해결 할 수 있다는것을 알게되었다. 

 

이와 같은 내용에 대해서 참고하고자 ChatGPT 답변내용을 첨부해본다. 

 


Unity의 Animator의 Update Mode에서 Unscaled Time은 시간 척도에 대한 개념입니다. 이것은 시간이 스케일링(변경)되지 않은 상태에서 애니메이션을 업데이트하는 데 사용됩니다. 

Unity에서 시간은 게임이 실행되는 동안의 흐름을 제어하는 데 중요한 역할을 합니다. 하지만 게임에서는 때로는 시간의 스케일링이 필요하지 않을 수 있습니다. 예를 들어, 게임이 일시정지되었을 때, 일부 애니메이션은 여전히 계속되어야 하지만 일시정지된 시간에 따라 진행되어서는 안됩니다. 이런 경우에 Unscaled Time이 유용합니다. 

Animator의 Update Mode를 Unscaled Time으로 설정하면, 애니메이션은 Time.timeScale이 1로 설정된 경우에도 시간의 스케일링을 받지 않고 진행됩니다. 따라서 게임의 일시정지나 슬로우 모션 같은 상황에서도 애니메이션이 계속해서 자연스럽게 재생됩니다.

그럼에도 불구하고, 게임 시간에 따라 애니메이션을 업데이트하려면 Animator의 Update Mode를 Normal로 설정하여 Time.timeScale을 사용할 수 있습니다.

또한, Unity의 Time 클래스에는 UnscaledDeltaTime이라는 개념도 있습니다. UnscaledDeltaTime은 시간 스케일링에 영향을 받지 않는 프레임 사이의 시간 간격을 나타냅니다. 이것은 주로 물리 엔진이나 기타 시간에 민감한 작업을 처리할 때 사용됩니다. UnscaledDeltaTime은 보통 FixedUpdate()나 Animator의 Unscaled Time에 사용됩니다.

 


 

그리고 추가적으로 시간을 멈추거나 슬로우를 걸때에 그러한 영향을 받지 않는 형태로 오브젝트가 동작하도록 하기 위해서는 해당 오브젝트에 UnscaledDeltaTime 을 이용해서 이 오브젝트의 경우 전체 Time.timeScale의 영향을 받지 않도록 하는 형태로 로직을 작성할 수 있다는것을 알게 되었다. 

현재의 경우는 게임을 일시정지 시킨후에 UI 만 정상적으로 동작하고 UI 에서 ReGame 버튼만 정상동작하면 되는 상황이기 때문에 다른 오브젝트에서 UnscaledDeltaTime을 사용할 상황은 아니지만, 다음에 특정 오브젝트는 시간흐름이 다르게 동작해야 하는 경우를 만나면 UnscaledDeltaTime을 이용해서 따로 로직을 구현해보도록 하자. 

 

Animator 컴포넌트에서 Update Mode 를 Unscaled Time 으로 선택해서       Time.timeScale = 0f; 인 경우에도 UI 의 애니메이션은 동작하도록 만들기.

 

+++

이 내용을 알아내는데 도움이 되었던 두가지 블로그 글을 첨부할것인데, 

첫번째와 두번째중 두번째는 첫번째 내용을 참고하여 작성한 글로 보여진다. 

이때에 첫번째 내용에서 댓글에 일시정지 구현시에 Time.timeScale = 0f; 형태로 구현하는 것이 아니라 다른 방향으로 인터페이스를 사용해서 구현하는 방식에 대해서 안내하는 댓글이 있어서 그것도 첨부하겠다. 현재는 일단 기능구현이 우선인 상황에서 Time.timeScale= 0f; 형태로 작성하는것을 우선적으로 시도해보려 하지만, 타임스케일을 건드리는것보다 다른 방법으로 일시정지를 구현하는것이 더욱 깔끔하고 마음에 들기 때문에 그 방법에 대해서 더욱 탐구해보고 다음에 그런 방향으로 한번 수정해보도록 하자. 

 

<첫번째>

https://gamedevbeginner.com/the-right-way-to-pause-the-game-in-unity/

 

The right way to pause a game in Unity - Game Dev Beginner

Learn the right way to pause a game in Unity. Including how to animate menus, move objects or run coroutines while the game is paused.

gamedevbeginner.com

 

<두번째>

https://koreanfoodie.me/983

 

유니티에서 일시정지 및 특정 물체 시간 정지 구현하기

Udemy 관련 개념 정리 및 Dev Log 를 기록하고 있습니다! 유니티에서 일시정지하기 유니티에서는 일시 정지 기능을 어떻게 구현하면 될까? 먼저 결론만 말하자면, Time.timeScale 값을 조절하여 Time.deltaT

koreanfoodie.me

 

 

 

<첫번째 내용중 timeScale의 수정이 아닌 인터페이스를 활용한 일시정지 구현에 대한 설명글>

Hi! Good article!

I use a different method because I don’t like to change the timeScale at any level (it just goes with my way of thinking, I guess).

What I do is to create an empty interface (IPausable) and when I want to pause the game, I traverse all the components in the scene and check if they are IPausable. If they are, I disable them:

AudioListener.pause = true;

var all = FindObjectsOfType( );

foreach( var c in all ) {
var p = c as Pausable;
var a = c as Animator;

var rb = c.GetComponent( );
if( rb != null )
rb.simulated = false;

if( p != null || a != null ) {
if( c.enabled ) {
_enabledStatesBeforePause.Add( c );
c.enabled = false;

}
}
}

I disable all the Animators too, and I tend to pause all particle systems, like this:

var pss = FindObjectsOfType( );

foreach( var ps in pss )
ps.Pause( );

This way, no matter what, the component that I want to be paused will be paused without side effects.

As you can see, I store the paused componentes in _enabledStatesBeforePause List, just to be able to resume them when pause finishes:

AudioListener.pause = false;

var all = FindObjectsOfType( );

foreach( var c in all ) {
var rb = c.GetComponent( );
if( rb != null )
rb.simulated = true;
}

foreach( var b in _enabledStatesBeforePause ) {
if( b != null )
b.enabled = true;
}

_enabledStatesBeforePause.Clear( );

And if I want to resume particle systems:

var pss = FindObjectsOfType( );

foreach( var ps in pss )
ps.Play( );

I hope this approach helps! I really found it very easy to work with, and no intrusive at all for the components. In other words, the components you code doesn’t have to be aware of pausing more than inheriting from IPausable.

 

 

+++

그리고 현재 Time.timeScale = 0f; 인 상황에서 씬을 리로드 할때 제대로 동작하지 않는 문제가 있는데, 

이와 연관 있을만한 첫번째 아티클에서의 댓글과 해당 아티클 작성자의 정보전달 부분이 있어서 덧붙인다. 씬을 리로드 할때 Time.timeScale을 다시 조정해주어야 하는 것으로 보인다. 

 

 

 

  Comments,     Trackbacks