유니티3D - 사운드 연주와 오브젝트 이동방법
상태바
유니티3D - 사운드 연주와 오브젝트 이동방법
  • PC사랑
  • 승인 2012.06.11 12:20
  • 댓글 0
이 기사를 공유합니다

유니티3D

사운드 연주와 오브젝트 이동방법
저번 호에는 유니티의 특장점과 오브젝트를 공중에서 떨어뜨리고 충돌 후 반사시키는 방법에 대해 알아 봤다. 이번 강좌에서는 오브젝트가 충돌할 때 사운드를 연주하고, 키보드를 이용해서 오브젝트를 이동하는 방법에 대해 알아보도록 하겠다.

박승제 [email protected]

‘저녁놀’이란 필명으로 안드로이드 커뮤니티인 안드로이드사이드에서 게임강좌를 진행하고 있다. ‘실전 앱 프로젝트 안드로이드 게임 개발편’, ‘따라하기 비주얼베이식 새내기편’을 비롯해 20여권의 지필서가 있다.
유니티3D: 유니티는 게임 엔진으로 알려져 있지만 게임 이외에도 앱, 건축, 디자인, 인테리어, 시뮬레이션, 의학, 군사 등 다양한 분야에서 활용되는 개발 플랫폼이다. 유니티사에서 개발한 이 게임 엔진은 2005년 유니티 1.0을 출시한 이래 세계 엔진 Top5에 선정됐고, 2010년 기술 혁신상을 수상했으며, EA 등의 기업에서도 정식으로 도입하고 있다. 

 
1. 오브젝트에 색깔 넣기
오브젝트에 색깔이나 무늬 등을 넣을 때에는 매트리얼(Material)을 사용한다. 매트리얼을 이용해서 오브젝트에 그림이나 색깔 등을 넣는 것을 매핑(Mapping)이라고 한다.

1.1 매트리얼 만들기
프로젝트 탭에서 Create 버튼을 눌러 폴더를 하나 만들고 이름을 Materials로 바꾼다. 반드시 폴더가 있어야 하는 것은 아니지만 프로젝트를 효과적으로 관리하기 위해 게임에 필요한 리소스는 종류별로 폴더를 만들어서 관리하는 것이 좋다. 새로 만든 폴더가 선택된 상태에서 Create 버튼을 눌러 매트리얼을 만든다. New Material이 만들어지면 이름을 m_ball로 바꾼다. 게임 개발에는 리소스가 많이 추가되므로 리소스를 구별하기 쉽도록 적절한 접두어를 사용하는 것이 좋다. 인스펙터의 Main Color로 표시된 부분을 클릭하면 아래그림과 같이 컬러를 선택하는 창이 나타난다. 컬러를 지정하면 Preview란에 표시된 공의 색깔이 바뀔 것이다.
 
1.2 매트리얼 적용
위에서 만든 m_ball을 마우스로 드래그해서 하이어라키 탭에 있는 공에 끌어다 놓는다. 프로젝트 탭의 리소스는 모두 반복적으로 사용할 수 있다. 따라서 하나의 매트리얼로 여러 오브젝트를 같은 색깔이나 무늬로 칠할 수 있다. 그러나 오브젝트를 각각의 색깔로 칠하는 경우에는 색깔별로 매트리얼을 만들어야 한다.

1.3 텍스처 추가
텍스처(Texture)는 오브젝트 표면에 입히는 그림이다. 프로젝트 탭에 새로운 폴더를 만들고 이름을 Textures로 바꾼다. 윈도 탐색기에서 이미지가 저장된 폴더로 이동한 후 탐색기의 파일을 프로젝트 탭으로 끌고 오면 그 파일이 프로젝트에 추가된다. 앞에서 만든 m_ball 매트리얼을 클릭한 후 방금 추가한 이미지 파일을 인스펙터의 None (Texture)로 표시된 영역으로 끌고 온다.


텍스처는 매트리얼로 설정한 컬러와 혼합되어 표시된다. 텍스처에 매트리얼의 컬러를 섞지 않을 경우에는 컬러를 흰색으로 설정한다. 이제 게임을 실행하면 무늬가 있는 공을 볼 수 있다.

2. 사운드 출력(Audio Source)
공이 바닥에 충돌할 때마다 ‘통~’ 소리가 나는 효과음을 넣고 싶다면 일단은 사운드 파일이 있어야 한다. 인터넷 등을 찾아보면 무료로 다운받을 수 있는 사이트가 많이 있으므로 적당한 파일을 다운받자. 그것이 여의치 않을 경우에는 윈도우에 있는 사운드 파일이라도 가져오자. 제어판▶소리 아이콘을 클릭하여 소리 창을 열고 찾아보기 버튼을 누르면 윈도의 사운드가 수록된 폴더가 열릴 것이다.

2.1 Audio Source 연결
유니티는 배경음악이나 효과음 등이 수록된 사운드 파일을 오디오 클립(Audio Clip)이라고 한다. Audio Source는 오브젝트에 오디오 클립을 연결하는 컴포넌트이다. 프로젝트 탭에서 Create 버튼을 눌러 폴더를 하나 만들고 이름을 Sound Files로 바꾼다. 앞에서 이미지를 추가한 것과 같은 방법으로 사운드 파일을 Sound Files 폴더에 넣는다. 유니티는 오디오의 재생이나 충돌 등의 판정은 이벤트가 필요한 오브젝트에서 직접 처리한다. 그렇다면 충돌을 일으키는 오브젝트는 바닥과 공인데 어느 쪽에서 연주해야 할까? 어느 쪽이던 상관이 없다. 그런데 곰곰 생각해 보면 바닥에는 여러 종류의 공이 충돌할 수 있을 것이고, 공마다 서로 다른 사운드를 연주해야 한다면 바닥의 입장에서는 충돌이 일어날 때 마다 어느 사운드를 연주할지를 판정하는 등의 문제가 생긴다. 이런 경우에는 각각의 공이 각자에게 할당된 사운드를 연주하도록 하는 것이 더 효율적이다.

공을 선택한 후 Component▶Audio▶Audio Source을 차례로 클릭해서 공에 Audio Source 컴포넌트를 추가하면 아래그림과 같이 인스펙터에 방금 추가한 Audio Source항목이 표시될 것이다. 현재 Audio Clip 항목이 None로 되어 있으므로 앞에서 추가한 사운드 파일을 여기로 끌고 온다. 사운드 파일을 사용할 때에는 Audio Source 컴포넌트를 사용한다는 것을 잘 기억해 두자.

 
 
Audio Clip에 사운드 파일을 연결하면 아래그림과 같이 디자인 탭에 오디오 클립을 표시하는 기즈모가 나타난다. 사운드 파일을 공에 직접 끌어다 두면 위의 과정이 자동으로 처리된다. 즉, 공에 Audio Source 컴포넌트가 추가된 후 컴포넌트에 사운드 파일이 연결된다.

다시 게임을 실행해 보자. 오디오 클립이 연주되긴 하는데 충돌 시에 들리는 것이 아니라 게임을 시작하자마자 연주된다. 이것은 오디오 클립이 자동으로 연주되도록 설정되었기 때문이다. Audio Source 컴포넌트는 기본 옵션이 자동 실행이므로 인스펙터에서 Audio Source의 Play on Awake라는 항목을 찾아 체크를 해제한다. 그런 다음 게임을 실행하면 그나마 들리던 사운드마저 들리지 않을 것이다.

2.2 Audio Clip 연주 스크립트 작성
사운드는 공이 바닥에 충돌할 때 발생해야 하므로 공과 바닥이 충돌하는 시점에 오디오 클립을 연주하도록 스크립트를 작성할 차례이다. 프로젝트 탭에서 폴더를 하나 만들고 이름을 jsScripts로 바꾼다. 유니티는 자바스크립트, C#, Boo 등의 언어를 사용할 수 있다. 언어의 특성상 C#과 Boo는 Class를 작성해야 하지만 자바스크립트는 Class가 필요하지 않으므로 프로그램이 더 짧고 간결할 뿐만 아니라 초심자들이 배우기가 쉽다. 따라서 이 강좌에서는 자바스크립트를 사용한다. 새로 만든 폴더를 선택한 상태에서 Create 버튼을 눌러 Javascript를 한 개 만들고 파일 이름을 jsBall로 바꾼다. 새로 만든 스크립트 파일을 더블클릭하면 아래그림과 같이 유니티의 에디터가 나타난다.

에디터의 첫 행은 #pragma strict로 되어 있고 그 아래에 Start( )와 Update( ) 두 개의 함수가 만들어져 있다. #pragma strict는 선언하지 않은 변수의 사용을 금한다는 의미이며, Start()는 게임이 실행될 때 맨 처음 한 번 실행되는 함수이다. 또, Update( )는 게임이 실행되면 매 프레임마다 호출되는 함수로 가장 빈번하게 사용된다. 위의 함수는 충돌 판정에는 전혀 도움이 되지 않으므로 전체를 지우고(굳이 지우지 않아도 상관없다)다음과 같이 입력한다. 스크립트는 대소문자를 구분하므로 정확하게 입력해야 한다.

<!-------- 소스 코드 -------->
function OnCollisionEnter(coll : Collision) {
audio.Play();
}
<!-------- 소스 끝 -------->
 
 
 
불과 3행의 간단한 코드이다. OnCollisionEnter( )는 사용자가 호출하는 것이 아니라 충돌이 발생하면 유니티가 자동으로 호출해 준다. 전문적인 용어로는 자동으로 호출되는 함수를 콜백(Callback) 함수라고 한다.
공은 충돌과 반사를 반복할 것이므로 이 이벤트 역시 그때마다 발생한다. 위의 코드에서 진한 색으로 표시된 단어(coll)는 변수명이므로 임의로 작성해도 되지만 나머지는 모두 유니티 예약어이다. 따라서 이것을 바꾸면 에러가 발생한다.
함수의 본체에 있는 audio.Play( )가 오브젝트에 설치한 Audio Clip을 연주하는 명령이다. 스크립트의 작성이 끝나면 Ctrl+S키를 눌러 프로그램을 저장하고 프로젝트 탭으로 돌아간다. 이제 방금 작성한 스크립트를 공에 연결할 차례이다. 프로젝트 탭에 표시된 스크립트를 공으로 가져다 두면 공과 스크립트가 연결되며, 인스펙터에 연결된 스크립트가 표시된다. 이제 게임을 실행하면 공이 바닥에 닿을 때마다 ‘통~’ 소리를 들을 수 있다.
3. Prefab의 활용
3.1 Prefab은 무엇인가?

화면에 공을 여러 개 배치해 두고 시간차로 떨어지도록 하고 싶다. 어떻게 할까? 이런 경우 다음의 2가지 방법으로 처리할 수 있다.
① 공을 여러 개 복제해서 배치한다.
② 공을 프리팹(Prefab)으로 만들어서 사용한다.
①의 경우 유니티는 복제된 공을 개별적인 오브젝트로 처리하므로 각각의 오브젝트에 메모리를 할당한다.
 
따라서 공이 많아지면 컴퓨터에 부담을 줄 수 있다. 프리팹(Prefab)은 오브젝트의 원본을 따로 저장해 두고 오브젝트가 필요할 때마다 원본의 정보를 이용해서 복사본을 만드는 메커니즘으로, 복제(Duplicate)에 비해 훨씬 효율적이다. 프리팹은 오브젝트를 새로 만드는 것이 아니라 이미 만들어진 오브젝트를 프리팹이라는 영역에 따로 저장하는 개념이다. 따라서 프리팹은 반드시 원본 오브젝트를 필요로 한다. 또 한 가지, 프리팹은 반복적인 사용을 위한 기술이므로 반복이 전혀 필요하지 않는 오브젝트(예를 들어 게임의 배경, 바닥 등)는 프리팹으로 만들지 않는다.

3.2 Prefab 만들기
프로젝트 탭에 폴더를 하나 만들고 Prefabs로 이름을 바꾼다. Create 버튼을 다시 눌러 Prefab을 하나 만들고 새로 만들어진 New Prefab을 pfBall로 이름을 바꾼다. 하이어라키 탭에 있는 공을 새로 만든 프리팹에 끌어다 두면 공이 프리팹으로 등록된다. 공이 프리팹으로 등록되면 하이어라키 탭에 표시된 공이라는 글자의 색깔이 진한 파란색으로 바뀌어 표시될 것이다. 이제 pfBall로 이름을 붙인 프리팹을 디자인 탭에 여기저기 배치한 후 게임을 실행하면 된다. 공이 바닥에 닿는 시간을 조절하기 위해서는 공의 높이(y)를 달리해야 할 것이다. 또, 공의 충돌 계수에 변화를 주기 위해 각 공의 Rigidbody에 있는 Drag 값을 바꿀 필요가 있다.

 
 
 
3.3 Scene 저장
유니티에서 만든 게임은 여러 개의 스테이지나 서로 다른 화면(예를 들어 메뉴 화면)으로 구성될 수 있다. 유니티는 각각의 스테이지나 화면을 Scene이라는 개념으로 다룬다. 각각의 Scene(이하 화면)은 프로젝트의 리소스와는 별도로 저장된다. 화면을 저장하지 않은 상태로 프로젝트만 저장하고 유니티를 종료하면 애써 디자인한 화면을 잃게 된다.
프로젝트 탭에 Scenes라는 새로운 폴더를 만든다. File▶Save Scene 메뉴를 클릭하거나 Ctrl+S를 눌러서 현재의 화면을 앞에서 만든 Scenes 폴더에 Scene_1로 저장한다.
화면을 저장해 두면 다음에 프로젝트를 불러올 때 저장된 화면이 자동으로 나타난다.

4. 오브젝트 움직이기(2)
앞에서 만든 게임은 자유 낙하를 이용한 것이므로 진정한 의미에서의 이동이라고 볼수 없다. 이제 오브젝트를 이동하는 방법에 대해 알아보자.

4.1 화면 디자인
앞에서 작업한 프로젝트에 기본적인 폴더를 만들어 두었으므로 그것을 가지고 작업하자(새로운 프로젝트에서 시작해도 된다). 새로운 화면을 만들기 위해 File▶New Scene메뉴를 누르거나 Ctrl+N키를 누른다. 새 화면을 만들면 디자인 탭에는 카메라만 나타난다. 화면을 아래 그림과 같이 디자인할 것이므로 디자인 탭에 표1의 오브젝트를 설치하고 속성을 설정한다.

 
 
4.2 오브젝트의 발사(AddForce)
오브젝트를 이동하는 방법은 몇 가지가 있지만 일단은 가장 쉬운 발사(Shooting)부터 시작하자. 발사는 정지된 물체에 외부에서 물리적인 힘을 주어 이동시키는 것이다. 물체를 발사하려면 발사되는 물체가 리지드바디 컴포넌트를 가지고 있어야 한다. 이번 프로젝트의 목표는 주인공의 옆에 있는 공을 벽을 향해 발사하는 것이다.
 
 
 
물체의 발사는 다음과 같은 형식으로 작성한다.
오브젝트.rigidbody.AddForce(방향 * 힘)
여기에서의 방향은 공간 벡터이다. 공간 벡터는 Vector3(x, y, z)와 같은 형식으로 사용한다.

4.3 방향과 공간 벡터
Vector3(x, y, z)에서 x는 수평, y는 수직, z는 오브젝트의 앞/뒤 방향이다. z축의 방향을 정하는 방식으로 왼손 좌표계와 오른손 좌표계가 있는데, 유니티는 왼손 좌표계를 사용한다. 왼손 좌표계는 z축이 오브젝트의 앞(전방) 방향이다. Vector3(0, 0, 1)이 오브젝트의 전진, Vector3(0, 0, -1)은 후진이다. 공간 벡터가 방향을 가리킬 때 통상적으로 (x,y, z)의 값을 -1, 0, 1의 어느 하나로 설정한다. 오브젝트가 이동하는 전후좌우의 방향을 벡터로 표시하면 다음과 같다

전진 Vector3(0, 0, 1)
후진 Vector3(0, 0, -1)
오른쪽 옆걸음 Vector3(1, 0, 0)
왼쪽 옆걸음 Vector3(-1, 0, 0)
제자리 점프 Vector3(0, 1, 0)
뛰어 내리기 Vector3(0, -1, 0)

왼손 좌표계는 x=좌우, y=상하, z=앞뒤이다. 제자리 점프는 오브젝트가 리지드바디 컴포넌트를 가지고 있고 Gravity 속성이 있는 경우에는 점프(위로 이동한 후 다시 착지)가 이루어지지만 그렇지 않는 경우에는 공중으로 떠오르는 상태가 된다.
그렇다면 Vector3(0, 1, 1)은 어떤 동작일까? 위(y)로 올라가면서 앞(z)으로도 이동하므로 작은 힘을 준 경우에는 점프해서 뛰기, 아주 큰 힘을 주면 포탄을 전방을 향해 45°각도로 발사하기가 될 것이다.
유니티는 상하좌우의 방향에 대해 상수를 정의해 두었으므로 (x, y, z) 대신 상수를 사용할 수 있다.

전진 Vector3.forward = Vector3(0, 0, 1)
후진 Vector3.back = Vector3(0, 0, 1)
오른쪽 Vector3.right = Vector3(1, 0, 0)
왼쪽 Vector3.left = Vector3(-1, 0, 0)
위쪽 Vector3.up = Vector3(0, 1, 0)
아래 Vector3.down = Vector3(0, -1, 0)
원점 Vector3.zero = Vector3(0, 0, 0)

위의 상수는 게임에서 오브젝트를 이동하는데 아주 빈번하게 사용하므로 잘 기억해 두는 것이 좋다.

 
 
 
3.4 스크립트 작성
앞에서 만들어 둔 jsScripts 폴더에 새로운 자바스크립트를 만들고 이름을 jsShoot으로 바꾼다. 이것을 더블클릭해서 에디터를 열고 다음과 같이 입력한다.

<!------------ source -------------------~>
#pragma strict
var power = 500; // 발사 속도
var ball : GameObject; // 발사할 오브젝트
function Start() {
ball.rigidbody.AddForce(Vector3.forward * power); // 오브젝트 발사
}
<!------------ 코드 -------------------~>

자바스크립트는 변수 선언 시 자료의 형(type)을 생략할 수 있다. 3행을 정확한 문법으로 작성하면 다음과 같다.
var power : int = 500;
위의 Start( ) 함수는 게임이 시작될 때 맨 처음 한 번 실행된다. Start( ) 함수에서 AddForce( )로 오브젝트를 발사하는 구조이므로 게임을 실행하면 공이 자동으로 발사될 것이다. Ctrl+S키를 눌러 스크립트를 저장하고 프로젝트 탭으로 돌아간다. 프로젝트 탭에서 방금 작성한 jsShoot을 하이어라키 탭에 있는 주인공에 끌어다 놓는다. 그런 다음 주인공을 클릭하고 인스펙터에 있는 스크립트 부분을 보면 방금 작성한 스크립트에서 선언된 변수 power와 ball이 표시되어 있다. ball로 표시된 곳으로 하이어라키 탭에 있는 공을 끌어다 놓는다.

 
이제 플레이 버튼을 눌러 게임을 실행하면 주인공 옆에 있는 공이 발사되어 벽과 충돌하는 모습을 볼 수 있다.
앞에서 공간 벡터를 설명할 때 Vector3(0, 1, 1)이 정면 45°로 발사한 것이라고 했으므로 스크립트의 5행을 바꿔서 설명대로 발사되는지 확인해 보자.
이것 외에도 Vector3( )의 값을 바꿔가면서 게임을 실행해서 Vector(x, y, z)의 방향을 확실하게 알아두는 것이 좋을 것이다.
 
 
 
 
4.5 키 입력으로 발사(GetButtonDown)
이제 키를 눌러서 발사하자. 키를 누르는 시점은 사용자마다 다르므로 특정한 이벤트에서 처리할 수 없다. 그래서 매번 호출되는 함수에서 처리한다. 앞에서 잠깐 언급한 바 있지만 스크립트를 작성할 때 Update( )라는 함수가 자동으로 만들어져 있는 것을 기억할 것이다. Update( )는 매 프레임마다 호출되는 함수이므로 초당 25~60회 정도 호출된다. 키 입력의 판단은 여기에서 처리한다.

유니티에서 사용자의 키를 판정하려면 Input Class를 사용한다.
Input.GetAxis("Horizontal") 좌우 이동키를 눌렀을 때 이동 방향
Input.GetAxis("Vertical") 앞뒤 이동키를 눌렀을 때 이동 방향
Input.GetKeyDown( ) 특정한 키를 눌렀는지 여부
Input.GetButtonDown( ) 특정한 키나 버튼을 눌렀는지 여부
Input.GetMouseButtonDown( ) 마우스 버튼을 눌렀는지의 여부
Input.GetTouch( ) 스마트폰의 화면을 터치했는지 여부

4.6 유니티의 입력 시스템
유니티는 단말기에 따른 입력 방식 차이를 해결하기 위해 입력 매체를 사용자가 직접설정할 수 있게 한다. 먼저 유니티의 입력 장치가 어떻게 구성되는지 알아보자. Edit▶Project Settings▶Input 메뉴를 누르면 할당되어 있는 키와 명칭이 모두 표시된다

우리는 발사에 사용할 키를 찾을 것이므로 Fire1을 살펴보자. 아래 그림과 같이 Fire1은 기본값이 왼쪽 Ctrl 키와 마우스 왼쪽 버튼으로 설정되어 있음을 알 수 있다.

 
우리도 이 키를 이용하기로 한다. 앞에서 작성한 jsShoot을 더블클릭해서 에디터를 열고 프로그램을 다음과 같이 수정한다.

■파일명 : jsShoot
<!------------ source -------------------~>
#pragma strict
var ball : GameObject;
var power = 500;
function Update() {
if (Input.GetButtonDown("Fire1"))
ball.rigidbody.AddForce(Vector3.forward * power);
}
<!------------ source -------------------~>

Update( ) 함수의 키보드 판정 부분이 GeKeyDown( )이 아니라 GetButtonDown( )으로 되어 있는 것을 기억해 두자. 이것은 마우스 왼쪽 버튼이 클릭한 상태를 구하는 함수로, Ctrl키와 마우스 왼쪽 버튼, 또 스마트폰의 화면 터치를 식별하는 기능이다.

 
4.7 오브젝트의 이동과 회전
화면에 있는 오브젝트는 모두 transform이라는 컴포넌트를 가지고 있다. transform은 인스펙터의 Transform 항목에 표시되는 정보로 물리적 위치, 회전각, 스케일에 대한 정보이다.

 
여기서 잠깐 대소문자의 표기 방식에 대해 알아보자. 유니티는 자료나 오브젝트의 형(type)을 명시할 때는 대문자, 오브젝트 자체는 소문자를 사용한다.
rigidbody 오브젝트의 리지드바디 컴포넌트 자체
 
 
Rigidbody Rigidbody Class 또는 Rigidbody형의 자료
transform 오브젝트의 컴포넌트 자체
Transform Transform Class 또는 Transform형의 자료
Class와 자료형(type)에 대한 개념이 없는 초심자는 헷갈릴 수 있다. 어떻든 오브젝트에 할당된 컴포넌트 자체를 가리킬 때는 소문자, 변수를 선언할 때는 대문자를 사용한다고 알고 있으면 된다.
오브젝트의 위치를 이동하거나 회전하면 트랜스폼의 정보가 바뀐다. 역으로 트랜스폼의 정보를 바꾸면 바뀐 내용이 오브젝트에 적용된다. 프로그램에서 트랜스폼의 정보를 바꿀 때에는 다음과 같은 함수를 사용한다.
이동 오브젝트.transform.Transrate(방향 * 속도)
회전 오브젝트.transform.Rotate(방향 * 속도)
크기 오브젝트.transform.localScale = Vector3(scaleX, scaleY, scaleZ)
우리는 방향을 지시하는 공간 벡터는 잘 알고 있으므로 Translate()로 속도만 조절해 주면 될 것이다.

4.8 키 입력과 방향
유니티는 오브젝트를 제어하는 키를 Horizontal, Vertical, Fire, Jump 등의 명칭으로 부른다. 먼저 현재 어떤 키가 할당되어 있는지 확인하자. Edit▶Project Settings▶Input메뉴를 클릭하고 인스펙터의 내용을 본다.
 
위 그림은 Horizontal(수평) 방향으로 이동할 때 사용하는 버튼과 키를 정의하는 것으로, 유니티의 디폴트값은 왼쪽(Negative)이 A, 오른쪽(Positive)은 D이다. Vertical 항목을 보면 W와 S로 되어 있음을 알 수 있다. 방향의 입력은 다음과 같이 처리한다.
var hor : float = Input.GetAxis("Horizontal"); // 좌우 : 키보드는 A, D
var ver : float = Input.GetAxis("Vertical"); 상// 하 : 키보드는 W, S
GetAxis( ) 함수는 입력장치(키보드, 마우스, 조이스틱)가 해당 방향으로 눌려진 값을 -1~1 사이의 값으로 구해준다. 물론 키를 누르지 않으면 0이 구해질 것이다.
 
 
4.9 오브젝트의 속도 설정
플랫폼의 성능과 상관없이 오브젝트가 일정한 속도로 이동하려면 거리와 시간과의 관계를 고려해서 프로그램을 작성한다.
속도 = 거리 ÷ 시간 오브젝트의 이동 속도(m/s)
거리 = 속도 × 시간 오브젝트가 1Frame에 이동할 거리
오브젝트의 이동은 먼저 초속 몇m로 이동할 것인지를 결정한 후, 그 속도를 내려면 1프레임에 얼마를 이동해야 하는지를 계산해서 처리한다. 유니티는 CPU의 성능과 상관없이 게임을 일정한 속도로 실행시키기 위해 직전 프레임과 현재 프레임 사이의 시간을 Time.deltaTime으로 구해준다. 오브젝트가 매 프레임에 이동할 거리는 초속×Time.deltaTime이다.
매 프레임의 이동 거리 = 속도(m/s) × Time.deltaTime

4.10 스크립트 작성
앞에서 작성한 스크립트를 다음과 같이 수정한다. 매 행마다 주석을 달아 두었다.

■파일명 : jsShoot
<!--------- source ---------->
#pragma strict
var speed = 5; // 이동 속도(m/s)
var power = 500; // 발사 속도
var ball : GameObject; // 공
function Update( ) {
var amtMove = speed * Time.deltaTime; // 매 프레임의 이동 거리
var ver = Input.GetAxis("Vertical"); // 앞뒤 이동 방향(벡터)
var hor = Input.GetAxis("Horizontal"); // 좌우 이동 방향(벡터)
transform.Translate(Vector3.forward * ver * amtMove); // 전후진
transform.Translate(Vector3.right * hor * amtMove); // 좌우 이동
if (Input.GetButtonDown("Fire1"))
ball.rigidbody.AddForce(Vector3(0, 1, 1) * power); // 45°로 발사
}
<!--------- source 끝 --------->
이제 프로그램을 실행하면 아래 그림과 같이 방향키로 오브젝트를 이동할 수 있다.

 
 
우리의 주인공은 눈에 보이기는 하지만 유령과 같은 존재라서 벽을 뚫고 다닐 뿐만 아니라 바닥을 벗어나도 추락하지 않고 허공을 활보한다. Rigidbody 컴포넌트가 없기 때문이다. 주인공에게 리지드바디 컴포넌트를 추가해 주면 두 가지 문제가 모두 해결된다.
 
4.11 오브젝트 회전(Rotate)
오브젝트의 회전은 다음과 같이 처리한다. 회전 오브젝트.transform.Rotate(회전방향 * 속도)위의 회전방향 역시 (x, y, z) 3축을 나타내는 Vector3이다.
아래 그림과 같은 오브젝트가 있을 때 오브젝트가 보는 방향이 z축, 오브젝트의 머리 위가 y축이다. 그러므로 오브젝트가 방향을 바꾸는 것은 y축 중심 회전이다. 즉, Vector3(0, 1, 0)×회전속도이다. 유니티의 회전 방향은 시계방향이 양(+)의 방향이며 60분법 각도(Degree)를 사용한다.

 
우리는 A나 D키를 누르면 좌우의 방향에 따라 -1~1의 값이 구해진다는 것을 알고 있으므로 이것을 이용해서 오브젝트를 회전시킨다. 오브젝트의 회전은 다음과 같이 처리한다.
오브젝트.transform.Rotate(Vector3.up * 회전속도)
위 식의 Vector3.up은 Vector(0, 1, 0)이다. 프로그램을 다음과 같이 수정하고 실행해 보자. 추가 및 수정할 곳을 주석에 표시해 두었다.

■파일명 : jsShoot
<!--------- source ---------->
#pragma strict
var speed = 5; // 이동 속도(m/s)
var rotSpeed = 120; // 회전 속도(각도/s) --- 추가
var power = 500; // 발사 속도
var ball : GameObject; // 공
function Update() {
var amtMove = speed * Time.deltaTime ; // 프레임에 이동할 거리
var amtRot = rotSpeed * Time.deltaTime ; // 프레임에 회전할 각도 -- 추가
var ver = Input.GetAxis("Vertical" ); // 전후진(벡터)
var ang = Input.GetAxis("Horizontal" ); // 좌우 회전 방향(벡터) -- 수정
transform.Translate(Vector3.forward * ver * amtMove ); // 전후진
transform.Rotate(Vector3(0, ang * amtRot, 0) ); // 회전 -- 수정 ①
if (Input.GetButtonDown("Fire1"))
ball.rigidbody.AddForce(Vector3(0, 1, 1) * power);
}
<!--------- source 끝 ---------->
① transform.Rotate(Vector3.up * ang * amtRot); 로 해도 된다.

 
이상으로 키보드를 이용해서 오브젝트를 이동 및 회전하고 발사하는 과정 등에 대해 알아보았다. 다음 호에서는 간단한 게임을 만들어가면서 유니티의 다른 기능에 대해 학습하게 될 것이다.


댓글삭제
삭제한 댓글은 다시 복구할 수 없습니다.
그래도 삭제하시겠습니까?
댓글 0
댓글쓰기
계정을 선택하시면 로그인·계정인증을 통해
댓글을 남기실 수 있습니다.