본문 바로가기

유니티 ML Agents/유니티 기초

4. 유니티 스크립트

 유니티 스크립트 기본 개념



스크립트 기본 개념


유니티는 자바스크립트와 C# 기반 스크립트를 지원하고 있다. 현재 대부분의 자료들이 C#을 사용하고 있기 대문에 이 책에서도 C# 기준으로 설명하도록 하겠다. C#은 마이크로소프트에서 개발한 객체지향 언어로써 JAVA와 비주얼C++과 유사한 문법을 가지고 있다. C# 문법을 별도로 공부하지 않더라도 어느 정도 객체지향 프로그래밍에 대한 경험이 있는 사람이라면 어렵지 않게 코드를 이해할 수 있다. 객체지향 프로그래밍 경험이 없는 사람이면 C# 기본 문법에 대해 먼저 공부하는 것이 좋다.



니티는 게임 오브젝트 중심으로 개발되며 게임 오브젝트의 구체적인 기능을 정의하는 것이 스크립트이다. 유니티 스크립트는 이벤트 기반으로 동작한다. 객체가 움직이거나 프레임이 바뀌면서 발생하는 모든 상황에 대한 이벤트가 사전에 정의되어 있으며 정의된 이벤트가 발생하면 유니티 엔진은 객체 내부에 정의된 이벤트 처리 함수를 호출한다. 프로그래머는 이벤트 처리 함수 안에 자신이 원하는 기능을 코딩하는 것이다.


사용자 정의 스크립트는 MonoBehaviour 클래스를 상속해서 만든다. 객체 지향 언어에서 상속이란 부모 클래스의 모든 속성과 동작을 물려 받는 것을 의미한다. 따라서 사용자 정의 스크립트는 MonoBehaviour 클래스의 모든 속성과 동작을 그대로 가져오게 된다. MonoBehaviour 클래스는 객체가 동작하기 위한 기본적인 기능을 제공하고 있으며 프로그래머는 사용자 정의 스크립트를 만들 때 자신이 필요한 함수를 선택적으로 재정의(Overriding) 하면서 구체적인 동작을 구현한다. 그림에서 보면 MonoBehaviour 클래스 안에 Start() 함수가 정의되어 있다. Start() 함수는 객체가 호출될 때 맨 처음에 호출되는 함수이다. 주로 객체 초기화에 많이 사용된다. MonoBehaviour 클래스를 상속받아 만들어지는 사용자 정의 스크립트는 초기화에 필요한 작업을 Start() 함수 안에 코딩하면 된다. 만일 초기화 작업이 필요 없다면 사용자 정의 스크립트 안에 Start() 함수를 재정의 할 필요가 없다. MonoBehaviour 클래스 안에 정의된 이벤트 처리 함수는 기본적으로 아무런 동작을 하지 않도록 설계되어 있으므로 사용자가 필요한 이벤트만 사용자 정의 스크립트 안에 구현하면 된다.


유니티 프레임과 이벤트 함수


애니메이션은 그림을 반복적으로 보여주는 방식으로 동작한다. 애니메이션을 구성하는 그림 하나 하나를 프레임이라 한다. 일반적으로 애니메이션에서는 1초에 24개의 프레임을 보여주고 게임에서는 60개의 프레임을 보여준다. 1초에 보여주는 프레임의 개수를 FPS(Frame Per Second)라 한다. 유니티는 보통 60 FPS를 사용한다. 60 FPS라 해서 정확하게 1초에 60개의 프레임을 보여주지는 않는다. 사용하는 컴퓨터 PC 환경에 따라 좀 더 적은 프레임을 보여줄 수 있다. 프레임이 바뀔 때 마다(이벤트 발생) 유니티는 Update 함수를 호출하는데 일반적으로 게임 로직을 처리할 때 필요한 코드를 Update 함수 안에 넣는다.


유니티에서는 물리적 충동을 처리하기 위해 FixedUpdate라는 함수를 제공하고 있다. 프레임 변경에 맞춰진 Update 함수와는 달리 FixedUpdate 함수는 유니티에 설정된 Fixed Timestamp 값에 따라 동작한다. Edit > Project Settings > Time 메뉴에서 값을 확인할 수 있다. Update 함수가 PC 환경에 따라 호출되는 주기가 바뀌는 것과 달리 FixedUpdate 함수는 고정된 주기로 호출되면 일반적으로 Update 함수 보다 자주 호출된다. 유니티에서는 물리적 충돌 체크할 때 FixedUpdate 안에 관련 로직을 코딩한다.

 

○ 게임 오브젝트에 스크립트 추가


스크립트 폴더 만들기


프로젝트에서 사용하는 다양한 스크립트를 저장하기 위해 Scripts를 폴더를 생성해 보자. 프로젝트 뷰에서 Assets를 선택하고 마우스 오른쪽 버튼을 클릭해서 Folder 메뉴를 통해 새로운 폴더를 만들어보자. 스크립트가 저장되기 때문에 이름을 Scripts로 변경하자.


PlayerController 스크립트 파일 만들기


스크립트 폴더를 선택해서 마우스 오른쪽 버튼을 클릭하고 Create 메뉴를 선택해서 C# Script를 생성하자. 생성된 스크립트의 이름을 PlayerController로 변경하자.


객체에 스크립트 추가


생성한 스크립트를 Player 객체에 추가하기 위해 PlayerController 스크립트를 선택한 다음 계층 뷰에 있는 Player 객체에 드래그 앤 드랍으로 가져다 놓으면 인스펙터 뷰에서 PlayerController 스크립트가 객체에 추가된 것을 확인할 수 있다.


스크립트 열기


스크립트를 편집하기 위해서는 스크립트를 편집할 수 있는 에디터로 먼저 스크립트를 열어야 한다. 스크립트를 여는 방법은 두 가지가 하나는 인스펙터 뷰에서 스크립트 컴포넌트를 클릭하는 것이고 다른 하나는 프로젝트 뷰에서 스크립트 파일을 클릭하는 것이다. 스크립트는 디폴트로 Visual Studio를 통해서 열린다. 기본적으로 만들어지는 PlayerController.cs 파일의 코드를 살펴보면 Start Update 함수가 빈 상태로 구현되어 있다. 앞에서 살펴 봤듯이 Start 함수는 초기화를 담당하고 Update 함수는 게임 로직 처리를 담당한다. 유니티에서 가장 많이 사용하는 함수를 디폴트로 만들어 준다.


○ 스크립트 개발하기


공 움직이는 스크립트 개념


이제 공을 움직이는 스크립드를 만들어보자. 우리의 목적은 사용자의 입력 값에 따라 공이 전, , , 우로 움직이는 동작을 구현하는 것이다. 스크립트 내부에는 사용자 입력을 처리하는 모듈과 입력에 따라 구체가 이동하는 동작을 처리하는 모듈이 필요하다. 이제 C# 코드를 하나씩 구현해 보면서 유니티 동작을 어떻게 정의하는지 알아보자.


공 움직이는 스크립트


공의 움직임을 구현하는 기본적인 스크립트 구조를 살펴보자. PlayerController는 두 개의 함수를 재정의 해서 구현했는데 초기화를 위해서 Start 함수를 사용했고 객체의 물리적 제어를 위해 Update 함수 대신 FixedUpdate 함수를 사용했다. 앞서 살펴본 스크립트 구조에서 Update는 게임의 로직을 제어하고 FixedUpdate는 물리적 충돌을 제어한다고 언급한 바 있다.


(1) 공의 움직임을 제어하기 위해 객체 내부에 있는 Rigidbody 컴포넌트를 GetComponent를 통해 가져와서 클래스 변수로 선언한 rb 변수에 저장한다.


(2) 사용자로부터 받은 입력을 처리하는 Input 클래스에 있는 GetAxis 함수를 사용했다. Horizontal Vertical 로 입력된 키보드 값을 가져온다.


(3) 코드 부분은 아니지만 유니티 프로젝트 Edit > Project Settings > Input 부분을 살펴보면 Horizontal Vertical이 어떤 키보드 키 값으로 처리되는지 확인할 수 있다.


(4) Rigidbody 컴포넌트에 객체의 이동을 위해 전달할 값은 Vector3 객체 형태로 전달한다. Vector3객체는 x, y, z 값을 담고 있는 자료구조 역할을 한다.


(5) Rigidbody 컴포넌트에서 제공하는 AddForce 함수를 통해 사용자로부터 입력 받은 값을 객체로 전달한다.


공 움직이기


Play 버턴을 누르고 키보드 전, , , 우 키를 번갈아 누르면 공이 움직이는 것을 확인할 수 있다. 공이 좀 느리게 움직인다면 속도를 조절할 수 있다. 속도를 위한 별도의 변수가 있는 것이 아니라 움직임을 나타내는 값을 크게 만들어 주는 것이다.


public 변수 사용한 속도 조절하기


(1) 클래스 변수로 speed public으로 선언한다. 클래스 변수를 public으로 선언하면 인스펙터 뷰의 스크립트 컴포넌트에 클래스 변수를 확인할 수 있다.


(2) AddForce 함수를 호출할 때 movement speed만큼 곱해서 전달한다. 사용자가 입력한 키 값보다 더 큰 값이 들어가서 이동을 위한 힘의 크기를 늘이는 원리이다.


(3) 인스펙터 뷰에서 Speed 값을 점점 키워가면서 프로그램을 실행시켜 보자. 값이 클 수로 키를 눌렀을 때 공이 더 빨리 움직이는 것을 확인할 수 있다.