본문 바로가기

유니티 게임 개발하기

유니티 게임 개발하기 (2) - 움직이는 오브젝트 만들기.

안녕하세요, 지난시간에 유니티와 첫 만남을 가졌던 초보 개발자 Windy 입니다.

지난 시간에 이어서, 오늘은 처음으로 유니티 안에서 무엇인가를 만들어 보려고 해요.

게임을 만들 때 가장 중요한 부분이라고 하면 역시, '내가 움직일 캐릭터', 그리고 캐릭터가 움직일 '무대' 가 뭐니뭐니해도 가장 기본적인 요소가 아닐까 싶어요.


그래서 오늘은, 우리들이 방향키로 움직일 수 있는 오브젝트를 한번 만들어 볼까 합니다.

'내가 움직일 캐릭터' 를 한번 만들어 봐요.


우선 그러기 위해서는 유니티 씬 화면 내부에 새로운 오브젝트를 만들어 넣는 법부터 알아봐야 하겠습니다. 같이 화면을 보시죠.



보시는 것과 같이, Hierarchy, 즉 '계층' 메뉴에서 마우스 오른쪽 클릭을 하시면, 

게임 오브젝트를 생성해서 추가해 주실 수 있습니다.

빈 오브젝트부터, 3D 오브젝트, 카메라, 오디오 등등 굉장히 여러가지 오브젝트들이 있는데, 우선 저희가 만들고자 하는 것은 '캐릭터' 와 '무대' 이니까, 먼저 화면과 같이

3D Object 메뉴의 Plane을 선택해 보겠습니다.



네 흰색의  plane, 판때기가 하나 생겼네요.게임 오브젝트답게 움직일 수도 있구요.

이제야 기본이라고 할 수 있는 바닥을 깔았군요.

참고로, 지금 보시는 스크린샷처럼 어떤 오브젝트를 계층 탭에서 파란색이 되도록 클릭하고,

씬뷰 위에 마우스를 올리고 F버튼을 누르시면, 그 오브젝트를 중심으로 시야가 옮겨져요.

지금이야 오브젝트가 하나니까 쓸 일이 없지만, 나중에 오브젝트가 많아 지면 굉장히 유용한 단축키일것 같네요.



오브젝트를 만들고, 계층 뷰에서 선택하셨으면, 옆의 인스펙터 메뉴를 확인해 봅시다.



여러가지 옵션들이 보이시나요?
가장 위에 보이는 흰색 창이 바로 이름입니다. 이름과 , 태그, 레이어를 정할수 있는 탭이 있지만 당장은 자세히 다룰 일이 없으니까 넘어가구요,

그 아래 진한 색으로 모여있는 속성들을 좀 다뤄보도록 하죠.

이 옵션들은 각각 한 칸당 하나의 '컴포넌트' 라고 합니다.

어떤 오브젝트의 여러가지 성질을 추가하거나 수정할 수 있는 부분이 바로 이 컴포넌트 부분.

여기에는 코드를 입력하는 스크립트부터, 텍스쳐를 씌우기 위한 텍스처 마테리얼까지 오브젝트가 가진 모든 정보를 표시하게 됩니다.

이 컴포넌트라는 말은 앞으로도 엄청나게 많이 쓸 수 밖에 없을것 같죠? 꼭 기억해 둡시다.




그중에서도 가장 먼저 눈에 띄는 게 바로 이 Transform입니다.

트랜스폼 컴포넌트는 어떤 오브젝트든, 심지어 그게 빈 오브젝트라고 해도 항상 있어야만 하는 필수적인 컴포넌트죠. 왜냐구요? 이 컴포넌트는 바로 위치정보를 가지고 있기 떄문이죠.

position이라는 메뉴에서는 x,y,z위치값,

rotation 메뉴에서는 기울기와 각도,

scale 메뉴에서는 각 축별로 크기를 속성으로 가집니다.

각각 벡터3의 변수라고 생각하시면 될 거 같네요.

어떻게 보면 오늘 가장 중요한 컴포넌트입니다. 오늘의 목표는 캐릭터를 '움직이게' 하는 거니까요. 벌써 감이 오시는 분들도 계시죠?

좀전의 트랜스폼 컴포넌트에서 위치 정보를 전부 0으로 초기화했습니다.

이 오브젝트뿐만 아니라, 어떤 오브젝트든 만드시고 나면 꼭 포지션을 필요한 위치로 초기화해서 확인해 줍시다.

이런 식으로 초기화를 잘 해 줘야 나중에 쓰기가 편하다고 해요.



다음은 똑같은 방법으로 캡슐 오브젝트를 추가해 줍시다.

포지션은 0,1,0 입니다. 0,0,0으로 맞추면, 캡슐의 절반이 땅에 묻히게 되거든요.



그리고 나면 다음과 같은 화면을 확인할 수 있습니다.

마우스 오른쪽 버튼을 클릭하고 드래그하면 이리저리 돌려서 화면을 보실 수도 있으니

잘 확인해 보세요. 이게 오늘 저희가 움직일 '캐릭터' 입니다.


이제 캡슐이 생겼으니, 계층 탭에서 캡슐을 선택하시고 인스펙터 메뉴를 보시면, 여러가지 

정보들 밑에 Add Component 메뉴가 있습니다.

말 그대로 새로운 속성을 추가하는 건데요, 기존에 있는 여러가지 속성들부터, 직접 만들 수 있는 스크립트까지. 많은 종류가 추가 가능합니다.

자, 우리는 한번 C#스크립트를 선택해서 추가해 봅시다.

스크립트 명은, 우리가 캡슐을 움직이기 위해 넣는 거니까 , Ctr로 할게요.



참고삼아 말씀드리면, 이렇게 미리 프로젝트 메뉴에서 오른쪽 버튼으로 스크립트나 몇가지 옵션을 만들어 두고 드래그&드롭으로 추가하실 수도 있으니 참고하세요!

이렇게 드래그하시면 컴포넌트로 적용되어 해당 옵션이 적용됩니다.

어쨋든, 어떤 방법으로든 C#컴포넌트가 추가되면..





이렇게 새 컴포넌트가 하나 추가됩니다.

이걸 더블클릭하시면 Edit script 메뉴가 있구요.

드디어 첫 코딩을 하게 되었네요. 들어가 봅시다.




그러면 이런 화면이 나옵니다. 유니티는 모노디벨로퍼를 메인으로 사용하고 있어서, 앞으로 스크립트 작성은 여기서 하게 되실 겁니다.

제가 리뷰를 만드느라 미리 코드는 작성을 해 뒀는데요, 같이 확인해 보도록 하죠.





코드는 크게 3부분으로 구성이 됩니다.

순서대로 전처리부, Start();, Update(); 입니다. 잘 기억해 둡시다.

처음 스크립트를 컴포넌트로 추가하고 나면, Start();, Update(); 이 두개만 있고 다른 내용은 없으니까요, 먼저 그부분에 대해서 설명해 드리도록 하죠.



public float moveSpeed = 5.0f;

public float moveRot = 0.5f;


시작 부분입니다. 위쪽에 설명해 드렸듯, 퍼블릭 변수는 바깥 컴포넌트에서 조정이 가능해지기 때문에 나중에 굳이 스크립트를 건드릴 필요가 없어져서 편한 거 같아요. 예를 들면 속도나 소리를 조절하기 쉽도록 이렇게 바깥에 꺼내놓으면, 나중에 이것저것 바꿔 가면서 실험해 볼 때 굳이 코드를 바꿔가면서 해볼 필요가 없죠. 편하네요!


private Transform tr = null;

다음으로 아래의 코드인데요, 이 코드는 Transform형 변수 tr을 만듭니다.

음, 좀더 쉽게 설명해 드리면요, 위쪽에서 보셧던 컴포넌트라는 개념은, 코드 상에서 '클래스'로 취급이 됩니다. 그래서 이 트랜스폼 클래스를 만들어서, 변수를 만들어 두고


tr = this.gameObject.GetComponent<Transform> ();


아래쪽 스타트 함수에서 이렇게 해 주면 , tr에 이 캡슐 오브젝트의 Transform 컴포넌트에 접근할 수 있는 주소가 저장이 됩니다. 

GetComponent<Component>()  의 사용법, 기억해 주세요. 자주 사용하게 될거 같네요.

물론, tr이라는 변수를 선언하는 대신 계속해서 

 this.gameObject.GetComponent<Transform> ();

를 사용해도 되겠지만, 코드를 쓰기도 불편하고 그때마다 계속해서 주소를 받아와야 되니까

비효율적인 작업이 되겠죠.

이런 부분을 보통 Start () ; 부분에서 미리 처리해 두게 됩니다.

미리 처리해 두고 접근할 수 있도록 해 두면 편하니까요!


참고로 - Start() ; 함수 외에도 start(); 라는 함수가 이미 등록되어 있어서 혼동해서 쓰시면 안된다고 해요. 조심해 주세요!



이제 업데이트 구문 안쪽입니다.

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

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

float rot = Input.GetAxis("Mouse X");

한 프레임마다 마우스의 x축 움직임, 세로, 가로의 입력을 받는 변수를 만드네요.

저희가 계속 입력하니까 이런 부분은 프레임마다 받을 수밖에 없죠. 




//transform.position += new Vector3 (0.0f, 0.0f, 0.1f);

//transform.position += Vector3.forward * 0.1f;

          ▲채택하지 않은, 하지만 가능한 움직이는 방법입니다.

 사용하지 않아 주석 처리해 뒀어요.

        

움직이는데는 여러가지 방법이 있죠, 제가 채택하지 않은,방법을 통해서 어떤 방법이 어떤 문제가 있는지 알아보도록 하겠습니다.

일단 position에 접근해서 직접 값을 추가해주는 방법이 있죠.

포지션은 벡터3 값이라고 말씀 아까 드렸었던거 같은데, 기억나시나요? 그걸 응용한 방법이에요. 하지만 이렇게 할 경우에는 입력키마다 추가적인 움직임이 생기기 때문에,

앞으로갈때 +1만큼 가고, 대각선으로 갈때 +1만큼 간다면,

앞과 옆 입력을 동시에 했을 때는 루트2 만큼의 속도로 진행하게 됩니다. 속도가 빨라지죠.

옛날 게임들에 이런 부분들이 조금 있는데, 조금 더 세련되게 하고 싶어서 이 방법을 채택하지 않았습니다.



벡터함수를 사용하는데도 방법이 있습니다.

vector.까지 입력하시면 작은 창이 뜨면서 참 벡터3의 여러가지 하위 옵션이 나와요.


* Vector3.forward = Vector3(0,0,1)

* Vector3.up      = Vector3(0,1,0)

* Vector3.right   = Vector3(1,0,0)

* Vector3.one     = Vector3(1,1,1)

* Vector3.zero    = Vector3(0,0,0)

* Vector3.Normalized -> 총 길이가 1인 단위벡터.


벡터 사용시에 가장 많이 쓰실 수 있는 부분입니다.  그냥 이런게 있다고 확인만 해 주세요.


Vector3 moveDir = (Vector3.forward * v) + (Vector3.right) * h;


  tr.Translate (moveDir.normalized * moveSpeed * Time.deltaTime);

tr.Rotate (Vector3.up*moveRot* Time.deltaTime*rot);


이제 실제로 움직이는 함수를 작성해 봤습니다. 위쪽에 썻던 것보다 조금 깔끔하게 쓰고 싶었는데, 그렇게 느껴지시나요?

 moveDir 라는 변수 안에 입력되는 벡터값들을 전부 저장해 두고, 

실제 트랜스폼에 넣어서 움직일 때는 노말라이즈 된 값에 속도, 그리고 델타타임을 곱해서 

원하는 속도가 일정하게 나오도록 했습니다. 변수이름 그대로, 방향값이 된 거죠.

DeltaTime 은 상수고요, 시간이 지날수록 값이 커집니다. 

프레임을 실행하는데 걸리는 시간단위가 길수록 그만큼 델타타임값이 늘어나면서,

말하자면 시간값 보정을 해주게 되겠습니다.



참고로 말씀드리면, 유니티쪽 뿐만 아니라 많은 코드 작성자들이


변수는 소문자, 클래스 이상급은 대문자로 시작합니다.

예를 들면 이런 식이죠.


moveSpeed <- 단어가 바뀌는 곳에서는 대문자로 알아보도록 써줌. 

하지만 첫문자가 소문자이므로 변수

MoveSpeed <- 이건 무브스피드라는 클래스


이런식으로 어느정도 개발자들끼리 함께 개발할 떄 헷갈리지 않도록 하는 작은 약속이 되겠습니다. 보통 혼자 만드시는분은 거의 없으시니까요.

이런 부분도 알아두시면 좋을 거 같아요.


코드는 이미 위에서 다 작성되었고요, 빌드를 해 보고 문제가 없으시다면 ctr+S로 세이브를 하고 얼른 실행시켜 보도록 합시다.



저는 잘 움직이네요! 여러분은 어떠세요?


오늘 리뷰는 여기서 마치겠습니다! 다음시간에 만나요~!