본문 바로가기

IT/유니티

12. 유니티 교육 (Sebastian Lague 강의2)

1. Prefab, Instantiate


항상 느끼는 거지만, 잘하는것과 잘 가르키는것은 다른거 같다.

아무리 많은 것을 알고 있어도, 가르치는것이 서툰 이가 있는가 하면, 

자신이 아는 것보다도 더 잘 가르치는 이가 있기도 하다. 


결국 누군가를 가르치는 것은 높은 수준의 커뮤니케이션 스킬이라고 할수 있지 않을까?

쩝..왜 이런말을 하냐면, 이전 지미 강의가 끝나고 세바스찬 강의를 듣고 있는데, 

어쩜 이렇게 귀에 쏙쏙 들어오게 잘 가르치는게 너무 이뻐죽겠다.


강의 하나만 들어도 정말 궁금하던것들이 싹다 풀리는 느낌이다.

우리 세바스찬 최고!


오늘은 유니티의 가장 중요한 포인트라고 할수 있는

Prefab이다.


몇년전부터 유니티에 관심이 있었을때, 유니티책이나 강의을 좀 보면 맨날 prefab...prefab하곤 했는데

이게 뭔가...라고 의문이 들었다.


결국 Prefab은 영어그래도 미리 만들어 높은 객체인것이다. 

언제든지 갔다 쓸수 있게.

물론 Hierarchy에서 duplication해서도 가능하다. 

하지만 이 듀플리케이션은 완전히 독립된 객체를 만드는것과 같기때문에,

만약 의자를 만들고 막 복제해놓았는데, 아참 쿠션 만드는것을 깜박했내라고 하면,

이미 복제해놓은 모든 의자에 쿠션을 따로 만들어 주어야 한다. 


하지만 프리팹을 쓴다면! 이 모든 문제는 단 한번에 해결할수 있다.

프래팹에서 끌어다가 쓴 객체는 다 프래팹과 연동되는것이기때문에, 일일이 다 고칠필요는 없는것이다.


프리팹을 만드는 방법은 간단하다 그냥 Hierarchy에서 드레그해서 애셋에 놓으면 된다.


이런 특성을 이해하고, 큐브몇개와 스피어하나로 의자를 Prefab으로 만들어 보았다.

그리고 스페이스바를 한번 누를때마다, 랜덤한 위치에 위자가 생성되도록 만들어보자


소스코드는 다음과 같다.



using UnityEngine;

using System.Collections;


public class ChairSpwaner : MonoBehaviour {


    public GameObject chairPrefab;


// Use this for initialization

void Start () {

}

// Update is called once per frame

void Update () {

        if (Input.GetKeyDown(KeyCode.Space))

        {

            Vector3 randomSpawnPosition = new Vector3(Random.Range(-10f, 10f), 0, 10 + Random.Range(-10f, 10f));

            Vector3 randomSpawnRotation = Vector3.up * Random.Range(0, 360);


            GameObject newChair = (GameObject)Instantiate(chairPrefab, randomSpawnPosition, Quaternion.Euler(randomSpawnRotation));

            newChair.transform.parent = transform;

        }

}

}


chairPrefab은 퍼블릭으로 만들어서 inspector에서 드래그로 넣어주었다.

대부분의 코드는 평이하고 이전에 써본 애들인데, 이번에 새로 나온 놈은 바로

Instantiate이다. 이 함수는 오브젝트를 생성시키는 놈이라고 생각하면 된다.

인자도 코드를 보면 바로 이해가 되리라 믿는다.

다만 문제는 이 Instantiate가 리턴시키는 놈은 gameObject가 아니라 그냥 object인것이다.

그래서 캐스팅하는 것을 잊지 말아야 한다.

gameObject로 캐스팅한 객체들은 모두 스크립트가 들어있는 객체를 부모로 둔다.

이러면 나중에 hierarchy에서 관리하기가 편하진다.




2. Script Communication


학원이나 교육센터에서는 c#이 유니티의 언어라서 c#을 잘해야 한다 라고 애기한다.

하지만 프로그래머로써 조금이라도 생각해보신분들은 이해하시리라 생각하지만, 언어는 프로그래밍에서 그렇게 중요하지 않다.

물론 특정 분야의 최고 전문가라면 다르겠지만, 대부분 코딩으로 빌어먹고 사는 입장에서 

언어 따질 시간은 없어.

저는 자바만 해서 C는 잘 몰라요. 헤헤..

이런 프로그래머를 누가 뽑아 주겠는가.

아~ 저는 C프로젝트만 해서 자바 프로젝트 설계는 못해요.

이따위 PM은 존재할수가 없다.


결국 언어는 그냥 수단일뿐, 기본적인 프로그래밍 소양이 있으면 어떤 언어를 사용하든 크게 상관이 없다.

그저 변수 선언이나, 몇가지 문법이 다를뿐이지 대부분의 코드는 대동소이하다.


이런 점에서 유니티에서 스크립트란 어쩌면 객체지향 언어에서의 클라스라고도 할수 있다.

그럼 클래스간의 통신은 어떻게 할까?

이거 엄청 중요하다. 가장 기본이고 결국 모든 프로그래은 이걸로 끝날것이다.

(쉽게 생각하면 그냥 클래스끼리 데이타 주고 받다가 끝나는게 겜이고 프로그램아니겠는가)


지미의 강의 에서는 그냥 두리뭉실하게 대충 설명하고 지나갔는데, 세바스찬은 이게 중요하다는것을 아는지

따로 한강의를 때서 설명해주었다.


우선 플레이어와 게임UI스크립트를 만든다.

자꾸 비교하는데, 지미의 강의처럼 그냥 되는데로 객체에 누더기처럼 

스크립트 붙여서 플레이가 되게만하는건 중요하지 않다.

그런건 누구나 할수 있다.


아무튼  두 스크립트를 만들고 통신을 하는 소스는 다음과 같다.


//Hierarchy의 이름으로 찾을때 

//GameObject playObject = GameObject.Find("Player");


//tag가 있을때

//GameObject playerObject = GameObject.FindGameObjectWithTag("Player");


//player = playerObject.GetComponent<E12_Player>();


//그냥 스크립트는 직접 찾는다.

player = FindObjectOfType<E12_Player>();

player.OnPlayerDeath += GameOver;


주석에 써있듯이 여러가지 방식으로 타 스크립트에 접근할수 있다.

단순히 hierarchy의 이름으로 접근해서 스크립트 컴포넌트를 반환받거나,

태그가 있다면 태그로 접근한후 똑같이 스크립트 컴포넌트를 반환받을수 있다.

그리고  가장 간단한거는 그냥 직접 스크립트를 찾아서 받는 방식이다. 


그리고 타 스크립트의 변수나 함수에 접근하고 싶다면, 반드시 퍼블릭으로 만들어 주어야 한다.

당연한거지만 언급하고 넘어간다.


하지만 여기서 중요한것은 이런 문법적인 것이아니다.

플레이어와 게임UI의 관계를 보자.


게임UI는 반드시 플레이어의 존재를 인식하고 있어야 한다. (당연한것이므로 이유는 생략)

하지만 플레이어는 게임UI를 인식해야만 할것인가?


그건 아니라고 생각한다. 왜냐하면 만약 플레이어가  게임UI를 인식한다는것은

결국 코딩상 플레이어와 게임UI는 땔수 없는 관계가 된다. 

그 플레이어는 반드시 그 게임UI를 사용해야만 하는 관계가 된다. 

(이건 엔지니어링적인 문제)


다음의 그림을 보자.


플레이어는 UI가 없다면 빨간부분이 에러가 날것이다. 

언급했듯이 코딩적으로 이미 UI를 집어 넣어기때문에, 이미 한덩어리가 된것과 마찬가지다.


반면에 UI의 경우는아래와 같다.

UI는 플레이어의 존재를 인식해야만 하기때문에, 상관없다.



그렇다면 아래와 같은 소스를 어떻게 해야 논리적으로 분리시키면서 연동할수 있을까?




해답은 바로 Action이라는 변수에 있었다.

이게 c#에 원래 있는 놈인지 어떤지는 모르지만, 결국 이런 스킬이 중요한거 같다.

이 Action은 마치 변수처럼 보이지만, event라고 한다. 

말그래도 변수이지만 결국 함수인것이다.

아직 정의 되지 않은 함수라고 생각하면 편할거 같다.

그래서 이것을 이용해서 다시 코딩하면 다음과 같다.


위와 같이 플레이어에서 액션 이벤트를 선언하고 그것 변수처럼 사용한다.

그리고 플레이어를 인식할수 있는 UI에서 플레이어의 액션 이벤트를 정의 해주면 된다.

문법이 독특하다. +=


위에서 모든것이 끝난거 같지만, 액션이벤트는 변수와 같기때문에 만약에 Null값이라면 버그의 원인이된다. 그러니까

if (OnPlayerDeath != null)

                OnPlayerDeath();

이렇게 처리하는게 좋을것이다.


아~~정말 유익한 강의 인거 같다. 이번에도 세바스찬 최고!!