상세 컨텐츠

본문 제목

[Unity] 유니티 소멸, 해제이벤트, 해제함수(OnApplicationQuit, OnDisable, OnDestroy 등등) 관련

게임엔진관련/유니티 엔진

by AlrepondTech 2019. 9. 4. 15:50

본문

반응형

 

 

 

=======================

=======================

=======================

 

 

 

 

 

 

 

 

출처: http://spieleprogrammierer.me/unity/2018/12/29/unity-decommissioning-event-function-types.html

 

원문: MonoBehaviour.OnApplicationQuit(), MonoBehaviour.OnDisable(), MonoBehaviour.OnDestroy() 
참고용 예제 저장소: Unity Practice (Sungkuk Park) 
최종 업데이트: 2018년 12월 30일

개요 (Overview)

본문은 Update 해제(decommissioning) 이벤트 함수 3형제인 OnApplicationQuit, OnDisable, OnDestroy를 소개하는 글이다. 각 함수에 해당하는 유니티 공식 문서를 참고했으며 예제 프로젝트를 빌드하면서 새로이 확인한 사항들도 본문에 추가했다. OnDisable의 경우는 최근 필자가 유니티 클라이언트 면접 당시 기출되었던 질문이므로 면접을 앞두고 있다면 한번 읽어봐도 좋을 것이다.

MonoBehaviour.OnApplicationQuit()

어플리케이션(application)이 종료되기 직전 모든 게임 내 객체들에게 전송된다.

에디터 상에서는 Play Mode를 종료할 때 호출된다.

참고 1: iOS 어플리케이션은 일반적으로 종료되는 대신 정지된다(suspended). 따라서, iOS 빌드의 경우 게임이 정지되는 대신 종료되게 만드려면 Player Settings의 “Exit on Suspend” 체크 박스를 활성화시켜야 한다. 그러지 않으면 이 경우 OnApplicationQuit 호출을 받을 수 없다. 만약 “Exit on Suspend”가 비활성화되어 있다면 OnApplicationPause가 대신 호출된다.

참고 2: 윈도우 스토어 앱이나 윈도우 폰 8.1의 경우 OnApplicationQuit 이벤트가 존재하지 않는다. 따라서 대신 focusStatus가 false와 같아질 때 OnApplicationFocus 이벤트 사용을 고려하라.

참고 3: WebGL의 경우 OnApplicationQuit을 구현할 수 없다. 이는 브라우저(browser)의 경우 탭(tabs)이 닫히는 방식이기 때문에 그렇다.

using UnityEngine; public class OnApplicationQuitExample : MonoBehaviour { private void OnApplicationQuit() { // Time.time은 현재 프레임이 시작되는 순간의 시간으로서 (읽기 전용), // 해당 시간은 게임이 시작된 이후 경과한 시간을 초로 나타낸 것이다. Debug.Log("어플리케이션이 " + Time.time + " 초 뒤에 종료되었습니다"); } }

예제 출력 결과: “어플리케이션이 1.980064 초 뒤에 종료되었습니다”

MonoBehaviour.OnDisable()

OnDisable은 해당 Behaviour가 비활성화 상태가 되면 호출된다.

OnDisable은 객체가 파괴될 때에도 호출되며, 이 때문에 해당 구간에서 자원 해제(cleanup) 코드를 사용할 수도 있다. 컴파일이 끝난 직후 스크립트를 다시 불러올 때에도 OnDisable이 호출되며, 스크립트가 로드된 이후 뒤이어 OnEnable이 호출된다.

참고: OnDisable 함수는 Start와 달리 코루틴으로 사용할 수 없다.

using System.Collections; using UnityEngine; public class OnDisableExampleClass : MonoBehaviour { private void OnEnable() { Debug.Log("OnEnable"); } private IEnumerator Start() { Debug.Log("Start"); yield return new WaitForSeconds(2.5f); Destroy(gameObject); } private void OnDisable() { Debug.Log("OnDisable"); } private void OnDestroy() { Debug.Log("OnDestroy"); } }

따라서 위의 OnDisableExampleClass가 유니티 상에서 활성화되었다고 가정할 때, 콘솔에 출력될 각 함수들의 호출 순서 내지 문자열은 다음과 같다:

OnEnable Start OnDisable OnDestroy

MonoBehaviour.OnDestroy()

부착된 Behaviour가 파괴되는 경우 OnDestroy 메시지를 받게 된다.

OnDestroy는 씬(Scene)이나 게임이 종료될 때 발생한다. 데이터 상에서 Play Mode를 중단시키는 경우에는 해당 어플리케이션을 종료시키게 된다. 이 경우에도 OnDestroy가 호출된다. 또한, 현재 씬이 닫히고 다음 씬이 로드된 경우에도 OnDestroy가 호출된다. 스탠드얼론(standalone) 어플리케이션의 경우는 씬이 종료될 때 OnDestroy가 호출된다. 하나의 씬의 종료는 일반적으로 새로운 씬이 로드된 경우를 말한다.

참고 1: OnDestroy의 경우, 해당 게임 객체의 상태가 활성화(active) 상태였던 경우에만 OnDestroy가 호출된다.

아래 예제 코드를 보면 OnDestroy의 동작 방식을 이해할 수 있다. OnDestroyExample1 스크립트가 실행되면 버튼이 하나 활성화된다. 이 버튼을 통해 OnDestroy를 호출한 뒤 OnDestroyExample2 스크립트의 실행으로 넘어간다. OnDestroyExample2 스크립트가 활성화되고 나면, 어플리케이션을 종료하는 방식으로 두 번째 OnDestroy를 호출할 수 있다. 만약 OnDestroyExample1 스크립트가 어플리케이션을 종료하는 식으로 중단되더라도 역시 OnDestroy가 호출되게 된다.

using UnityEngine; using UnityEngine.SceneManagement; public class OnDestroyExample1 : MonoBehaviour { private void Start() { Debug.Log("Start1"); } private void OnGUI() { if (GUI.Button(new Rect(10, 10, 250, 60), "Scene 2로 이동")) { Debug.Log("Exit1WithButton"); SceneManager.LoadScene("OnDestroyExample2"); } } // Start() 이벤트 함수가 호출되기 전에 메시지를 생성한다 private void OnEnable() { Debug.Log("OnEnable1"); } // 게임이 종료되거나 다른 씬으로 이동할 때 메시지를 생성한다 private void OnDestroy() { Debug.Log("OnDestroy1"); } }

using UnityEngine; public class OnDestroyExample2 : MonoBehaviour { private void Start() { Debug.Log("Start2"); } private void OnEnable() { Debug.Log("OnEnable2"); } // 게임이 종료되거나 다른 씬으로 이동할 때 메시지를 생성한다 private void OnDestroy() { Debug.Log("OnDestroy2"); } }

따라서 위의 OnDestroyExample1 스크립트가 존재하는 씬을 시작으로 버튼을 눌러 OnDestroyExample2 스크립트가 존재하는 씬으로 이동한 후 어플리케이션을 종료한다고 가정할 때, 콘솔에 출력될 각 함수들의 호출 순서 내지 문자열은 다음과 같다:

OnEnable1 Start1 Exit1WithButton OnDestroy1 OnEnable2 Start2 OnDestroy2

 

 

 

 

=======================

=======================

=======================

 

 

 

 

 

출처: http://milennium9.godohosting.com/wordpress/?p=83

 

C#의 event를 사용할 때 delegate에 등록을 했으면 반대로 해제를 하는 과정이 필요합니다.

OnClick += OnClickButton;

OnClick -= OnClickButton;

 

그런데 Unity에서 이를 사용할 때 주의해야 할 점이 있습니다.
바로 Start(), OnDestroy() 함수에서 이벤트를 등록하는 것은 위험하다는 점입니다.

Start() 함수는 Object가 생성된 다음번 Update 함수가 호출되기 전에 호출됩니다.
OnDestroy() 함수는 Object가 소멸되기 직전에 호출됩니다.
그래서 Start() 함수에서 이벤트 등록을 하고 OnDestroy() 함수에서 이벤트 해제를 할 수도 있습니다.

여기서 문제는 OnDestroy 입니다.
Object가 생성되자마자 SetActive(false)를 호출 하면 Start 도 호출되지 않지만 그 상태로 Destroy 해버리면 OnDestroy도 호출되지 않습니다.

이렇게 되면 문제가 없지만 Start가 호출된 이후에 SetActive(false)를 호출한 뒤 Destroy를 해버리면 이벤트가 등록은 되지만 해제는 되지 않은 채 Object는 소멸되는 좋지 않은 상황이 발생해 버립니다. 그 상태에서 event가 발생하면 null 객체의 멤버 함수가 호출되는 최악의 상황이 발생합니다. C#인데도 메모리에 잘못접근하는 거 같아 보였어요. ㅠㅠ

이런 문제를 방지하기 위해서 C#의 이벤트를 사용할 때는 OnEnable과 OnDisable을 사용하기를 추천합니다.

 

 

 

 

=======================

=======================

=======================

 

 

 

 

 

출처:ㅊhttps://flystone.tistory.com/m/110?category=293083

 

Prefab 을 public GameObject variable 로 연결하면 1개가 살아있다.

- Resource 로 옮기고 Resource.Load 후 Instantiate 해준다음 Resource.UnloadUnusedAsset으로 로드했던 prefab을 해제시키자.

 

Texture WWW 혹은 다른곳에서 load 한 texture 들은 사용하지 않을때

-  DestroyImmediate 로 꼭 해제시켜줘야 한다. DestroyImmediate 해주면 바로 memory 에서 해제된다.


GameObject Destroy 는 memory 를 바로 해제시키지 않는다.
    - Resource.UnloadUnusedAssets 를 해야 memory 에서 해제된다.
    - GameObject 를 DestroyImmediate 해도 포함되있는 Texture, material, 등은 memory에서 해제되지 않는다.

Load 한 Texture 들을 Member 로 가지고 있으면 GameObject Destroy 시 memory 해제 안된다.
     - Texture 는 개별 DestroyImmediate 하여 바로바로 해제하자.

 

 

 

 

=======================

=======================

=======================

 

 

 

 

 

출처: https://sangh518.github.io/record/unity-on-pause-quit/

 

유니티로 게임을 만들면 홈버튼을 눌러서 비활성화할 때와 게임을 종료할 때의 처리를 진행해야할 필요가 있다. 이러한 기능들은 유니티에서 제공하고 있기 때문에 MonoBehaviour가 지원하는 기본 함수를 사용하여 간단하게 적용할 수 있다.

OnApplicationPause

OnApplicationPause는 홈버튼을 눌러 어플을 비활성화하거나 다시 활성화했을 때 실행되는 함수로, bool값을 매개변수로 받는다.

 

//앱의 활성화 상태를 저장하는 변수

bool isPaused = false;

void OnApplicationPause(bool pause)

{

          if (pause) { isPaused = true; /* 앱이 비활성화 되었을 때 처리 */

}

else

{

          if (isPause) { isPaused = false; /* 앱이 활성화 되었을 때 처리 */ } }

}

OnApplicationQuit

OnApplicationQuit은 앱이 꺼질 때 실행되는 함수다. 별다른거 없고 그냥 쓰면 된다.

 

void OnApplicationQuit()

{

     /* 앱이 종료 될 때 처리 */

}

 

 

 

=======================

=======================

=======================

 

 

 

반응형


관련글 더보기

댓글 영역