2. Scripting Tutorial - 스크립팅 튜토리얼

Unity3D 2012. 6. 19. 11:38
반응형

1. 이번 튜토리얼의 목적

스크립팅은 유저가 유니티에서 게임의 행동 또는 규칙을 정의하는 방법이다. 유니티를 위해 권장하는 프로그래밍 언어는 자바스크립트이다. 그러나 C# 또는 Boo를 사용할 수도 있다.

하얀뱀:

원문에는 자바스크립트로 작성이 되어있지만 제가 번역하면서 모두 C#으로 변경할 것입니다. 그러므로 자바스크립트로 공부하실 분들은 원문과 함께 보세요.

이번 튜토리얼에서는 스크립팅의 핵심을 다루고 어플리케이션 프로그래밍 인터페이스(API)의 핵심 요소를 소개할 것이다. API는 당신이 개발시간을 단축시키고 게임개발에 집중할 수 있도록 미리 작성된 코드라고 생각할 수 있다. 이 기본 정책을 잘 이해하는 것은 유니티의 모든 파워를 가지기 위해 필수적인 것이다.

2. 선수지식

이 튜토리얼은 유니티의 스크립팅 요소에 집중하므로, 당신이 이미 GUI 튜토리얼과 친숙하다고 가정한다.

하얀뱀 :

원문에는 자바스크립트를 사용하므로 별도의 코드에디터를 사용하는 방법이 기술되어있지 않지만, 저는 C#을 사용할 것이므로 C#에 가장 좋은 비주얼 스튜디오를 코드에디터로 설정하는 방법을 설명드리겠습니다. 우선 비주얼 스튜디오를 먼저 설치하세요. 그리고 메인 메뉴의 Edit > Preference 를 선택하면 나타나는 창에서 External Script Editor 옆의 드롭다운 버튼을 누르면 비주얼 스튜디오가 나타날 것입니다. 그것을 선택해 주시기만 하면 앞으로 스크립트 코드를 작성하거나 수정할 때 자동으로 비주얼스튜디오가 실행되게 됩니다. 만약 비주얼 스튜디오를 선택했는데도 설정창에 나타나지 않을 경우에는 Browse 버튼을 누르고 비주얼 스튜디오 실행파일을 직접 지정해 주시면 됩니다.

하얀뱀 :

유니티에서 제공하는 기본 스크립트 파일에 오류가 있어서 아래의 내용들을 따라하다 보면 지속적으로 경고메시지가 뜨게 됩니다. 이는 매킨토시와 윈도우에서 사용하는 줄바꿈 기호가 다르기 때문에 나타나는 현상으로 이를 제거하기 위해 제가 경고가 나타나지 않는 파일을 작성하여 첨부하였습니다. 이 파일을 다운로드하여 C:\Program Files\Unity\Editor\Data\Resources 폴더에 덮어쓰기 하시면 됩니다.

3. 이름짓기 관습들

시작하기 전에, 유니티에서 사용하는 몇가지 관습에 대해서 알려주겠다.

변수들 - 소문자로 시작한다.

함수들 - 대문자로 시작한다.

클래스 - 대문자로 시작한다.

팁 : 유니티 API 또는 예제 코드를 살펴볼 때 단어들의 첫번째 문자를 주의깊게 살펴봐라. 이것은 당신이 오브젝트간의 관계를 더 잘 이해할 수 있도록 도와줄 것이다.

4. 플레이어 입력

우리의 첫번째 프로그램을 위해 우리는 유저가 단순한 게임월드를 움직일 수 있도록 허용할 것이다.

장면 설정하기.

  1. 유니티를 시작하라.

납작한 큐브를 사용하여 유저가 걸어다닐 수 있는 면을 생성하자.

  1. 큐브를 생성하고 스케일 값을 X(5), Y(0.1), Z(5)로 설정하라. 그것은 거대하고 납작한 평면을 닮아야 한다. 이것의 이름을 Plane으로 변경하라.

  1. 두번째 큐브를 생성하고 그것을 Plane의 중앙에 위치시켜라.

  1. 그리고 Point Light(점광원)를 생성하고 그것들이 잘 보이도록 큐브의 위쪽에 위치시켜라.

  1. File > Save As 를 선택하여 장면을 저장하라.

우리의 첫번째 스크립트.

우리는 이제 게임 프로그래밍을 할 준비가 되었다. 우리는 메인 카메라의 위치를 제어함으로써 플레이어가 게임월드 주변을 움직일 수 있도록 할 것이다. 이것을 위해 우리는 키보드로부터 입력을 받아들이는 스크립트를 작성할 것이다. 그리고나서 해당 스크립트를 메인 카메라에 붙일것이다.

하얀뱀 :

여기서부터는 원문의 내용을 모두 C#으로 변경하면서 설명문도 C#에 맞게 제가 임의로 변경하였습니다.

  1. 빈 스크립트를 생성하는 것으로 시작한다. Assets > Create > C Sharp Script 를 선택하여 스크립트 파일을 생성하고 이름을 Move로 변경하라.

  1. Move 스크립트를 더블 클릭하면 Start(), Update() 함수를 가진 클래스가 작성된 코드와 함께 비주얼 스튜디오가 열릴 것이다. Start() 함수는 Update() 함수가 실행되기 전에 호출이 된다. Update()함수는 매 프레임마다 호출이 된다.

하얀뱀 :

참고로 클래스의 이름을 꼭 스크립트 파일명과 동일하게 변경을 해 주셔야 합니다.

게임오브젝트를 움직이기 위해서는 그것의 위치 속성을 변화시킬 필요가 있다. transform에 속해있는 Translate 함수는 우리가 이것을 가능하게 한다. Translate 함수는 X, Y, Z 움직임을 위한 3개의 인자값을 필요로 한다. 우리는 메인카메라를 화살표키로 움직이기 위하여 키가 눌렸는지를 알아내는 코드를 첨부할 것이다.

public class Move : MonoBehaviour

{

    // Use this for initialization

    void Start()

    {

       

    }

    // Update is called once per frame

    void Update()

    {

        float dx = Input.GetAxis("Horizontal");

        float dy = Input.GetAxis("Vertical");

        transform.Translate(dx, 0, dy);

    }

    // 초당 이동 스피드.

    public float speed = 5.0f;

}

Input.GetAxis() 함수는 -1 ~ 1 사이의 값을 반환한다. Horizontal 축에서 왼쪽 화살표키는 -1, 오른쪽 화살표키는 1의 값으로 매핑이 되어있다.

카메라가 위쪽 방향으로 움직이지 못하도록 하기 위해 Y 좌표 값에 0을 주었음을 상기하라.

Input.GetAxis()함수에 사용된 Horizontal 과 Vertical 축은 입력 설정에 미리 정의가 되어있다. 그 이름과 매핑된 키는 Edit > Project Settings > Input 에서 쉽게 변경할 수 있다.

  1. Move 스크립트 파일을 열고 대소문자에 주의하며 위의 코드를 작성하라.

스크립트 붙이기.

이제 우리의 첫번째 스크립트가 작성되었는데, 게임오브젝트가 이 행동을 가지도록 어떻게 하는가? 우리는 이 스크립트를 게임오브젝트에게 붙여야 한다.

  1. 이것을 하기 위해, 스크립트에 정의된 행동을 가지기 원하는 게임오브젝트를 먼저 클릭하라. 우리의 경우는 메인 카메라이다.

  1. 다음으로 메인메뉴에서 Components > Scripts > Move를 선택하라. 이것은 카메라에 스크립트를 첨부한다. 당신은 Move 컴포넌트가 Inspector 창에 나타나는 것을 알 수 있다.

팁 : 당신은 프로젝트 뷰에서 스크립트 파일을 카메라로 드래그하여 첨부할 수도 있다.

  1. Play 버튼을 눌러 게임을 실행하라. 당신은 화살표키 또는 W,A,S,D키를 이용해 카메라를 움직일 수 있을 것이다.

당신은 아마도 카메라가 약간 빠르게 움직인다고 생각할 것이다. 카메라의 스피드를 제어하기 위해 더 나은 방법을 살펴보자.

델타 시간 (Delta Time).

이전 코드는 Update() 함수안에 있었으므로, 프레임당 일정한 움직임을 가지게 된다. 하지만 이보다는 초당 일정한 움직임을 가지도록 하는게 당신의 게임오브젝트가 예측 가능하도록 움직이게 하는 더 나은 방법이다. 이를 위해서 Input.GetAxis() 함수의 반환값과 Time.deltaTime 을 곱해야 한다.

public class Move : MonoBehaviour

{

    // Use this for initialization

    void Start()

    {

       

    }

    // Update is called once per frame

    void Update()

    {

        float dx = Input.GetAxis("Horizontal") * Time.deltaTime * speed;

        float dy = Input.GetAxis("Vertical") * Time.deltaTime * speed;

        transform.Translate(dx, 0, dy);

    }

    // 초당 이동 스피드.

    public float speed = 5.0f;

}

  1. Move 스크립트 파일의 내용을 위의 코드로 업데이트하라.

Move 클래스의 멤버변수로 speed 변수가 선언되어 있음을 주의하라. 이것은 노출 변수(exposed variable) 라고 불리운다. 이 변수는 이 스크립트를 가진 게임오브젝트를 선택하면 Inspector 창에 나타날 것이다. 노출 변수는 코드를 변경하는 것보다 더 쉽게 변화를 줄 수 있어 유용하게 사용된다.

5. 변수 연결하기

GUI를 통해서 변수를 연결하는 것은 유니티의 매우 강력한 기능이다. 이것은 유니티 GUI에서 드래그 앤 드롭함으로써 코드안의 변수에 할당이 된다. 이것은 아이디어를 쉽고 빠르게 시험해 볼 수 있게 한다.

우리는 플레이어(메인 카메라)를 따라다니는 스포트라이트(spotlight)를 생성함으로써 변수를 연결하는 시범을 보일 것이다.

  1. GameObject > Create Other > Spotlight 를 선택하여 장면 뷰에 스포트라이트를 추가하라. 그것을 다른 게임오브젝트에 가까이 이동하라.

  1. 새로운 스크립트 파일을 생성하고, 이름을 Follow로 변경하라.

우리가 원하는 것을 생각해보자. 우리는 스포트라이트가 메인 카메라가 어디있든지 바라보기를 원한다. 이것을 위해서 transform.LookAt()함수가 존재한다. 만약 당신이 ”이것을 어떻게 하지?”라고 생각하기 시작했다면 많은 코드가 이미 유니티 API에 존재함을 기억하고 언제나 이를 체크하라.

LookAt()함수를 위한 파라미터로 우리는 무엇을 사용해야 하는가? 우리는 게임 오브젝트를 하드코딩할 수 있다. 그러나 우리는 GUI 를 통해서 변수를 할당하기를 원한다. 그러므로 우리는 단지 노출 변수를 만들 것이다. Follow 스크립트는 아래와 같이 보여야 한다.

public class Follow : MonoBehaviour

{

        // Use this for initialization

        void Start()

        {

        }

        // Update is called once per frame

        void Update()

        {

                transform.LookAt(target);

        }

        public Transform target;

}

  1. Follow 스크립트를 스포트라이트에 첨부하라. 그러면 Inspector 창에서 target 변수를 볼 수 있다.

  1. Hierarchy 뷰에서 메인 카메라를 Inspector 창의 target 변수로 드래그하라. 이것은 target 변수로 메인 카메라를 할당하게 되고, 스포트라이트는 이제 메인카메라를 바라볼 것이다. 스포트라이트가 다른 오브젝트를 바라보기 원한다면, 해당 오브젝트를 드래그하기만 하면 된다.

  1. 게임을 실행하라. 장면 뷰를 보면 스포트라이트가 메인 카메라를 따라다니는 것을 볼 수 있다.

6. 컴포넌트에 접근하기

게임오브젝트는 여러개의 스크립트 또는 컴포넌트를 가질 수 있는데 종종 다른 컴포넌트의 기능 또는 변수에 접근할 필요가 있다. 유니티는 이것을 GetComponent() 함수를 통해 허용한다.

우리는 점프버튼을 누를 때마다 큐브를 바라보게 만들 또다른 스크립트를 스포트라이트에 추가할 것이다.

우리가 무엇을 해야하는지 생각해보자.

1. 점프버튼이 눌렸는지를 감지해야 한다.

2. Follow 스크립트는 스포트라이트가 바라봐야할 대상인 target 변수를 포함하고 있다. 우리는 이 변수에 새로운 값을 할당할 필요가 있다. 우리는 큐브를 위한 변수를 하드코딩할 수 있다. 하지만 우리는 GUI를 이용할 것이다.

  1. 새로운 스크립트 파일을 만들고 Switch로 이름을 변경한 후 아래의 코드를 작성하라.

public class Switch : MonoBehaviour

{

        // Use this for initialization

        void Start()

        {

                followScript = GetComponent<Follow>();

                prevTarget = followScript.target;

        }

        // Update is called once per frame

        void Update()

        {

                if (Input.GetButtonDown("Jump"))

                {

                        // Unity GUI에서 타겟 할당하는 방법.

                        //followScript.target = switchToTarget;

                }

                if (Input.GetButtonUp("Jump"))

                {

                        followScript.target = prevTarget;

                }

        }

        // Unity GUI에서 타겟 할당하는 방법.

        public Transform switchToTarget;

        // 다른 스크립트에 접근하기.

        private Follow followScript;

        private Transform prevTarget;

}

Follow는 GetComponent() 함수의 인자로 사용되고 그 결과값으로 Follow에 대한 참조가 반환됨을 명심하라. 이로써 우리는 target 변수에 접근할 수 있게 된다.

  1. 스포트라이트에 Switch 스크립트를 첨부하고 Inspector 창에서 switchToTarget 변수에 큐브를 지정하라.

  1. 게임을 실행하라. 주변을 움직여 스포트라이트가 평상시처럼 당신을 따라다니는지 확인하라. 그때 스페이스바를 누르면 스포트라이트가 큐브를 바라보아야 한다. 

코드로 작업하기.

조금 전에 우리는 GUI를 사용하지 않고 코드를 이용하여 변수를 할당하는 것이 가능하다고 언급했었다. 어떻게 하는지 살펴보자.

이것은 오로지 GUI를 이용한 방법과 비교하기 위한 것 뿐임을 기억하라.

코드로 이것을 수행하기 위한 방법에는 2가지가 있다.

1. 게임오브젝트의 이름을 이용하기.

게임오브젝트의 이름은 Hierarchy 뷰에서 볼 수 있다. 우리는 이 이름을 GameObject.Find() 함수의 인자로 사용할 것이다. 코드는 아래와 같다.

public class Switch : MonoBehaviour

{

        // Use this for initialization

        void Start()

        {

                followScript = GetComponent<Follow>();

                prevTarget = followScript.target;

        }

        // Update is called once per frame

        void Update()

        {

                if (Input.GetButtonDown("Jump"))

                {

                        // Unity GUI에서 타겟 할당하는 방법.

                        //followScript.target = switchToTarget;

                        // 소스코드에서 타겟을 직접 할당하는 방법 1 : 오브젝트 이름 사용.

                        followScript.target = GameObject.Find("Cube").transform;

                }

                if (Input.GetButtonUp("Jump"))

                {

                        followScript.target = prevTarget;

                }

        }

        // Unity GUI에서 타겟 할당하는 방법.

        public Transform switchToTarget;

        // 다른 스크립트에 접근하기.

        private Follow followScript;

        private Transform prevTarget;

}

2. 게임오브젝트의 태그를 이용하기.

게임오브젝트의 태그는 오브젝트를 찾기위해 사용되어지는 텍스트이다. 내장된 태그를 보기 위해서 Inspector 창에 있는 태그(Tag) 버튼을 클릭하라. 당신은 당신만의 태그를 만들 수 있다는 것도 알아야 한다. 특정한 태그로 오브젝트를 찾기 위한 함수는 GameObject.FindWithTag() 가 있다. 우리는 완전한 코드는 아래와 같다.

public class Switch : MonoBehaviour

{

        // Use this for initialization

        void Start()

        {

                followScript = GetComponent<Follow>();

                prevTarget = followScript.target;

        }

        // Update is called once per frame

        void Update()

        {

                if (Input.GetButtonDown("Jump"))

                {

                        // Unity GUI에서 타겟 할당하는 방법.

                        //followScript.target = switchToTarget;

                        // 소스코드에서 타겟을 직접 할당하는 방법 1 : 오브젝트 이름 사용.

                        //followScript.target = GameObject.Find("Cube").transform;

                        // 소스코드에서 타겟을 직접 할당하는 방법 2 : 오브젝트 태그 사용.

                        followScript.target = GameObject.FindWithTag("Cube_tag").transform;

                }

                if (Input.GetButtonUp("Jump"))

                {

                        followScript.target = prevTarget;

                }

        }

        // Unity GUI에서 타겟 할당하는 방법.

        public Transform switchToTarget;

        // 다른 스크립트에 접근하기.

        private Follow followScript;

        private Transform prevTarget;

}

하얀뱀 :

private 변수는 Inspector 창에 노출되지 않습니다.

원문에는 태그를 추가하는 방법이 없어 제가 따로 추가하는 방법을 설명드리겠습니다.

  1. 큐브를 선택하고 Inspector 창에서 태그 버튼을 누른 후 Add Tag...를 클릭합니다.

  1. Tags 글자 왼쪽의 ▶모양 화살표를 눌러 확장시킵니다.

  1. Element 0 글자 오른쪽의 빈 공간을 클릭하고 Cube_tag라고 입력합니다. 그러면 그 아래 자동으로 Element 1 이 추가되는데 이는 또다른 태그를 추가할 때 사용하고 지금은 사용하지 않습니다.

  1. 다시 큐브를 선택하고 Inspector 창에서 태그 버튼을 누른 후 Cube_tag를 클릭합니다.

이제 위에 작성한 코드가 정상적으로 수행될 것입니다.

7. 인스턴스 만들기.

종종 게임 실행 도중에 오브젝트를 생성하기를 원할 때가 있다. 이것을 위해 우리는 Instantiate 함수를 사용한다.

유저가 발사 버튼(마우스 왼쪽 버튼)을 누를 때마다 새로운 게임오브젝트가 생성되게 하는 방법 (인스턴스화 하는 방법)을 알아보자.

1. 우리가 인스턴스화 할 오브젝트는 어느것인가?

2. 우리는 그것을 어디에 인스턴스화 할 것인가?

어느 오브젝트를 인스턴스화 할지 고려하는 문제를 해결하는 최적의 방법은 이것을 노출 변수로 만드는 것이다. 이것은 인스턴스화 하기 원하는 오브젝트를 변수위로 드래그할 수 있게 한다.

어디에 인스턴스화 할 것인가에 대한 문제에 대해서, 우리는 단지 유저(메인 카메라)가 현재 위치하는 곳에 게임오브젝트가 생성되록 할 것이다.

Instantiate 함수는 3가지 인자를 필요로 한다. (1) 생성하고자 하는 오브젝트 (2) 오브젝트의 위치값 (3) 오브젝트의 회전값

완전한 코드는 아래와 같다.

public class Create : MonoBehaviour

{

        // Use this for initialization

        void Start()

        {

        }

        // Update is called once per frame

        void Update()

        {

                if (Input.GetButtonDown("Fire1"))

                {

                        Instantiate(newObject, transform.position, transform.rotation);

                }

        }

        public Transform newObject;

}

transform.position과 transform.rotation은 이 스크립트가 첨부된 오브젝트의 위치값과 회전값임을 잊지마라. 우리의 경우에는 메인카메라가 될 것이다.

그러나 오브젝트가 인스턴스화 될 때 오브젝트를 프리팹으로 만드는게 보통이다. 우리는 이제 큐브를 프리팹으로 만들 것이다.

  1. 우선, Assets > Create > Prefab을 선택하여 빈 프리팹을 만들고 이름을 Cube로 변경하라.

  1. 큐브 게임오브젝트를 Hierarchy 뷰로부터 프로젝트 뷰안의 Cube 프리팹위로 드래그하라. 프리팹 아이콘이 변화하는 것을 주시하라.

이제 우리는 스크립트 코드를 작성할 수 있다.

  1. 새로운 스크립트 파일을 생성하고 이름을 Create로 변경한 후 위의 코드를 작성하라.

  1. 이 스크립트를 메인카메라에 첨부하고 Cube 프리팹을 newObject 변수에 지정하라.

  1. 게임을 실행하고 평상시처럼 주변을 이동하라. 발사 버튼을 클릭할 때마다 (마우스 왼쪽 버튼 또는 Ctrl키) 새로운 큐브가 나타나는 것을 볼 수 있다.

8. 디버깅

디버깅은 당신의 코드에서 에러를 수정하고 찾아내는 기술이다. 유니티는 Debug 클래스를 통해 도움을 제공한다. 우리는 이제 Debug.Log()함수를 살펴볼 것이다.

로그(Log)

Log() 함수는 유저가 유니티 콘솔에 메시지를 보내는 것을 허용한다. 이것을 하는 이유는 아래와 같다.

1. 실행 도중에 코드의 특정 부분에 도달했는지 증명하기 위해.

2. 변수의 상태를 출력하기 위해.

우리는 이제 발사 버튼을 누를 때 유니티 콘솔에 메시지를 보내기 위해 Log()함수를 사용할 것이다.

  1. Create 스크립트 파일을 열고 if 코드 안에 있는 Instantiate 코드 아래에 다음 내용을 추가하라.

Debug.Log(“Cube created”);

  1. 게임을 실행하고 발사 버튼을 클릭하라. 이제 유니티 GUI의 하단에 ”Cube created”가 나타나는데, 유니티 콘솔 창을 검사하기 위해 이것을 클릭할 수 있다.

보기(Watch)

디버깅을 위한 또 다른 쓸모있는 기능은 private 변수를 노출시키는 것이다. Debug 모드가 선택되면, Inspector 창에 private 변수가 보이게 되지만 그것은 수정되지 않는다.

이것의 시범을 보이기 위해, 우리는 우리가 생성한 큐브의 개수를 private 변수로 만들어 노출시킬 것이다.

  1. Create 스크립트를 열고 다음 두 줄을 추가하라.
  2. (1) cubeCount 라고 부르는 private 변수를 추가하라.
  3. (2) 큐브를 인스턴스화 할 때마다 이 변수의 값을 증가시켜라.

완전한 코드는 아래와 같다.

public class Create : MonoBehaviour

{

        // Use this for initialization

        void Start()

        {

        }

        // Update is called once per frame

        void Update()

        {

                if (Input.GetButtonDown("Fire1"))

                {

                        Instantiate(newObject, transform.position, transform.rotation);

                        Debug.Log("Cube created");

                        cubeCount++;

                }

        }

        public Transform newObject;

        public int cubeCount = 0;

}

  1. 게임을 실행하고 Inspector창을 오른쪽 클릭하여 Debug모드를 선택한 후 큐브를 생성하기 위해 발사 버튼을 몇 번 클릭하라. Inspector 창에서 cubeCount 변수가 어떻게 변화하는지를 살펴보아라.

9. 공통 스크립트 타입

C# 스크립트 파일이 생성될 때마다 Start() 함수와 Update() 함수가 기본적으로 포함이 된다. 이번에는 이와같이 공통으로 사용되는 다른 함수들에 대해서 논의할 것이다.

FixedUpdate()

고정 프레임으로 실행되기 원하는 코드를 이 함수안에 작성하라. 예를 들어 아래와 같이 Rigidbody에 힘을 적용할 때 이 함수를 사용한다.

// 매 프레임마다 rigid body 에 위쪽으로 힘을 적용한다.

void Fixedupdate()

{

        rigidbody.AddForce(Vector3.up);

}

Awake()

이곳에 작성한 코드는 스크립트가 초기화될 때 호출된다.

Start()

이 함수는 Awake() 함수 후에 그러나 Update() 함수 전에 호출된다. Start()와 Awake()의 다른 점은 Start()는 스크립트가 사용가능(Inspector 창에서 체크박스가 선택되었을 때) 할 때만 호출이 된다는 것이다.

OnCollisionEnter()

이곳에 있는 코드는 게임오브젝트가 다른 게임오브젝트와 충돌하였을 때 수행된다.

OnMouseDown()

이곳에 있는 코드는 GUIElement 또는 충돌영역을 가진 게임오브젝트를 클릭하였을 때 수행된다.

OnMouseOver()

이곳에 있는 코드는 GUIElement 또는 충돌영역을 가진 게임오브젝트위에 마우스가 올라오면 수행된다.

이러한 함수들에 대한 더 자세한 정보는 유니티 API를 참고하라.

반응형
: