Unity 코드 분석 겸 공부


Unity 3D로 모바일 퀴즈 게임을 만들기 위해 작업중이다. 코드 분석을 하면서 새로 공부한 내용을 적어보았다.

MonoBehaviour

1

1. Mono

.Net은 MS에서 C언어에 자바의 장점을 수용하여 개발한 MS Windows 프로그램 개발 및 실행 환경, 언어이다. .NET은 네트워크와 UI 등의 많은 작업을 캡슐화 하여 코딩의 효율성을 극대화 하였다. 이를 사용하기 위해서는 .Net 프레임워크가 설치 된 윈도우 환경이 있어야 했지만, 다른 플랫폼에서 .Net 프레임워크를 사용하기 위해 개발된 것이 MS에서 인수한 자마린(Xamarin)사의 Mono. Mono는 .Net 프레임워크의 오픈소스 개발 플랫폼으로서 크로스플랫폼 어플리케이션의 개발을 지원하며 C#과 CLI에 기반을 두고 있다. Mono를 활용한 대표적 크로스 플랫폼 개발 도구가 유니티, 자마린이다.

1-1. Unity의 behaviour script

유니티에서 하나의 스크립트는 그 자체로 하나의 클래스를 의미.

  • 클래스 : 속성(properties), 메서드(method)등을 하나의 객체로 묶은 데이터 타입. 유니티에서 하나의 스크립트는 각각 properties, variables, instructions, functions를 가지며 사용자가 원하는 순간에 해당 스크립트를 호출할 수 있다. 모든 스크립트는 behaviour component이다.
  • Behaviour는 활성화(Enable), 비활성화(Disable)할 수 있는 component. 즉, 껐다 켰다 할 수 있는 동작(behaviour)이며, 이는 캐릭터의 동작, 환경, 게임 내 흐름을 제어하는 프로그램 자체가 될 수도 있다.
  • Component : GameObject에 부착되는 모든 것들이 상속받는 기반 클래스

1-2. MonoBehaviour

MonoBehaviour는 Unity의 모든 스크립트가 상속받는 클래스이다. 사용자가 Unity 엔진의 작동 방식을 이해하지 못해도 코드를 쓸 수 있도록 미리 만들어 둔(built-in) behaviour 클래스이자 스크립트 명령들의 집합. 이 덕분에 모든 스크립트는 유니티 엔진에 의해 호출(invoke)되는 콜백(callback)함수들을 이용할 수 있게 됨. 콜백함수 예시(Reset, Awake, Start, Update, OnGUI, OnDestroy 등등)

1-3. 생명주기

2

함수의 실행 순서이다. 알아두면 좋을 것 같다.

1-4. 주요 콜백 함수

3

  1. Reset : 유니티 에디터에서 오브젝트 생성 후 인스펙터 뷰에서 리셋을 눌러줄 때 실행된다. 객체의 속성을 초기 값으로 설정해 줄 때 사용한다.
  2. Awake : 프리팹이 인스턴스화 한 직후, 스크립트가 호출되자마자 오브젝트 활성화 여부와 상관없이 실행 된다. 모든 오브젝트가 초기화 된 후 호출되기 때문에 GameObject.Find 같은 명령문을 안전하게 사용할 수 있다. Awake 함수는 언제나 Start 함수 전에 호출되는 점에 주의. (StartCoroutine 을 사용할 수 없다.)
  3. OnEnable : 다른 초기화 함수와 달리 하나의 라이프 사이클 내에서 여러번 호출 될 수 있다. 인스펙터뷰에서 체크 및 스크립트 내에서 SetActive 함수로 게임 오브젝트를 활성화 할 때마다 호출 된다.
  4. Start : Update 함수가 호출되기 전에 한번만 호출된다. 다른 스크립트의 모든 Awake가 모두 실행된 이후에 실행되며 Awake와 달리 오브젝트가 활성화 되어 있어야 호출 된다. Awake 이후 호출되므로 예를들어 A 객체의 Awake 함수에서 동적 생성한 멤버를 B객체의 Awake 함수에서 접근할 경우 오브젝트 들의 Awake 함수 호출 순서는 임의로 정할 수 없으므로 B객체의 Awake 가 먼저 호출 되어 NullReferenceExecption 을 발생 시킬 수 있다. 이럴 경우 동적 생성은 Awake 에서 하고 동적 생성되는 멤버에 접근하는 초기화 코드는 항상 Awake 이후로 보장되는 Start 에 넣는 것이 좋다.
  5. FixedUpdate : 프레임과 상관없이 무조건 시간 기준(default 0.02초. 변경 가능)으로 호출 되는 Update 콜백이기 때문에 주로 물리 엔진을 사용하는 경우 일정 시간 간격으로 힘을 가하거나 체크할 때 사용한다. 프레임 속도가 기준 시간 속도보다 오래 걸릴 정도로 느려질 경우 한 프레임에서 여러번 호출 될 수 있다.
  6. Update : 매 프레임마다 호출되는 가장 일반적인 Update 함수. 오브젝트가 활성화 되어 있어야 호출 되며 프레임 단위이기에 호출 시간 간격은 프레임에 따라 변한다.
  7. LateUpdate : 모든 Update 계열 콜백들이 실행되고 나서 호출된다. Update 함수에서 캐릭터를 이동 시킨 후 LastUpdate에서 캐릭터의 좌표를 추적해 카메라의 좌표를 이동시키는 등의 경우에 사용한다.
  8. OnDisable : 게임 오브젝트 또는 스크립트가 비 활성화 되었을 때 호출된다. (StartCoroutine 사용 불가)
  9. OnDestroy : 해당 오브젝트가 파괴 되기 전 프레임의 Update 함수 실행 후 호출 된다. 일반적으로 라이프 사이클 내에서 사용한 자원들을 돌려 놓는 작업을 이곳에서 하게 된다.
  10. OnApplicationQuit : 앱이 종료 되기 직전에 모든 오브젝트에서 호출된다. 에디터에서는 플레이 모드 중지할 때 호출 된다.

1-5. MonoBehaviour의 특징

MonoBehaviour를 상속받은 스크립트 파일은 그 자체로 사용할 수 없다. GameObejct의 Component 형태로 등록되어 있어야 한다. 그래서 해당 클래스를 적용할 빈 GameObject를 Unity Hierarchy 에 추가한 후 Inspector 창에 이 스크립트 파일을 등록하는 것. 코드에서 해당 클래스를 가져오려면

GameObject객체에 GetCOmponent<GameManager>();

형태로 가져와야 한다. MonoBehaviour를 상속받은 클래스는 new로 동적할당할 수 없다.

이때는

  1. GameObject.Instantiate 함수를 통해 해당 스크립트가 Component로 추가된 오브젝트의 인스턴스를 생성,
  2. 기존 생성된 GameObject 객체에 AddComponent();하여 사용할 수 있다.

Class

4

상속

class 자식클래스이름 : 부모클래스이름 {}
//생성자는 상속이 되지 않으며 객체 생성 시 부모 클래스의 생성자가 자동으로 호출됨, private으로 선언된 멤버는 상속할 수 없음.
sealed class ~ {} // 이 클래스는 상속시킬 수 없다.

set, get 접근자

각각 속성을 읽거나, 새 값을 할당할 때 사용. OOP에서 정보 은닉(information hiding)을 위해 클래스 내부에서만 사용할 수 있도록 private로 접근을 제한해 버림.

Information hiding이란? : 클래스 내부의 필드나 메소드와 같이 객체가 가지고 있는 것들을 외부에서 접근하지 못하게 숨기는 것 그렇다면 사용하는 이유는?

  1. 필요한 정보만을 외부로 노출
  2. 안정성 위해. 보안위해.

메소드 재정의(virtual, override)

부모 클래스의 메소드를 자식 클래스에서 다시 정의하고 싶을 때.

  1. virtual : 자식 클래스에서 메소드를 재정의하고 싶을 때 재정의 될 부모 클래스의 메소드에 사용 => 순수 가상함수랑 가상함수에 대한 것도 후에 더 알아봐야겠다.
  2. override : 부모 클래스 내에서 virtual로 선언된 메소드를 재정의하겠다는 표시

멤버 숨기기(new)

new 지정자를 사용하면 부모 클래스의 멤버를 숨길 수 있게 된다.

Upcasting and Downcasting

  1. 다형성(polymorphism)이란? : OOP에서는 “하나의 객체가 여러 개의 형태를 가질 수 있는 능력” … 메소드의 오버로딩, 오버라이딩과 관련이 있다.
  2. upcasting : 자식 클래스의 객체가 부모 클래스의 형태로 변환되는 것
  3. downcasting : 부모 클래스의 객체가 자식 클래스의 형태로 변환되는 것

Upcasting 과 downcasting도 코드 예시를 통해 더 자세히 공부해야겠다.

Inspector창에서 제목(header) 작성하기 ([Header(string str])

5

예를 들어 코드에 이렇게 작성하면,

6

아래와 같이 inspector 창에 header text가 뜬다. 유용한 기능인듯.

7

=> 관련이 있는 필드들을 그룹화 할 수 있다.

Serialization

8 Serialization : 클래스 객체의 데이터를 파일이나 DB에 저장하거나 웹서비스 등으로 네트워크 상으로 전송할 수 있는 것.(복합 데이터 형식을 스트림에 읽고 쓰게 해주는 매커니즘) class, struct, enum(열거형), deligate를 직렬화하여 스트림에 읽고 쓰는 것이 가능해진다.

Coroutine과 IEnumerator

9 유니티에서 화면의 변화를 일으키기 위해서는 Update() 함수 내에서 작업하게 됨. Update는 매 프레임을 그릴때마다 호출된다. 하지만 여러 프레임에 걸쳐 어떤 작업을 수행해야 한다면 어떻게 해야 할까? => 기기의 성능 등에 따라 Frame drop 발생. 코루틴은 프레임과 상관없이 별도의 서브 루틴에서 원하는 작업을 원하는 시간만큼 수행하는 것을 가능하게 한다.

void Start(){
    StartCoroutine(RunCoroutine());
}

IEnumerator RunCoroutine(){
    yield return new WaitForSeconds(1.0f);
    yield return new WaitForSeconds(1.0f);
    yield return new WaitForSeconds(1.0f);
}

StartCoroutine에는 IEnumerator를 반환하는 함수를 인자로 받으며 이 함수는 실행된 결과를 의미하는 것이 아니라 함수 포인터와 같은 개념으로 사용됨

  • 얘도 더 공부해야 할 것 같다.(http://blog.naver.com/PostView.nhn?blogId=dj3630&logNo=221459387675)