Unity 3D Instantiate() example
유니티 3D에서 Instantiate() 함수를 이용하여 동일한 오브젝트를 실행시에 다수개 생성하는 예제
게임에서 동일한 오브젝트가 다수개 사용되는 경우는 포탄이나 미사일 등과 같은 오브젝트일 것이다. 유니티에서는 이와 같은 오브젝트를 개발시에 한개만 준비해 놓고 실행시에 이용자가 다수개를 요구하면 그 때마다 해당 오브젝트의 인스턴스를 원하는 수만큼 생성해 낼 수 있다.
이때 사용하는 함수가 Instantiate()이며 이 함수를 이용하여 동일한 모양의 인스턴스를 생성하려면 Prefab 이라는 유니티가 요구하는 형식을 준비해야 한다.
즉, 유니티는 Prefab을 이용하여 실행시에 동일한 게임 오브젝트를 원하는 수만큼 생성할 수 있는 API를 제공하고 있다.
여기서는 대포에서 포탄이 발사되는 동작을 실린더와 구를 이용하여 작성하려고 한다. 그리고 Prefab을 생성하는 절차에 대해서도 알아본다
우선 포탄은 공중에서 중력의 영향을 받아서 결국 땅으로 떨어지게 되는데 이러한 물리적인 운동은 Physics 콤포넌트를 이용하므로 이에 대해서도 적용하는 방법을 알아보고자 한다.
아래의 그림과 같이 큐브 2개가 위 아래로 같은 위치에 있는 Scene을 구성하고 Play 버튼을 눌러 실행해보면 그 어떤 동작도 발생하지 않는 것을 볼 수있다.
만약 실물환경이라면 공중에 떠 있는 박스는 당연히 아래로 떨어져야 하는데 이 큐브에는 Physics 콤포넌트를 적용하지 않았기 때문에 아무런 동작이 없다.
위쪽의 박스가 아래로 떨어지도록 Physics 콤포넌트를 적용하려면 다음과 같은 절차에 따른다. 참고로 박스와 같은 물체는 관절체와는 다른 강체(Rigid Body)에 속한다. 먼저 위에 위치한 큐브를 Hierarchy 뷰에서 선택한 후에 아래의 순서대로 진행하면 된다.
위와같이 설정하면 위에 위치한 큐브를 선택할 경우 Inspector 뷰에 RigidBody 콤포넌트가 추가되고 Use Gravity 항목이 디폴트로 선택되어 있기 때문에 위에 위치한 큐브는 중력을 받아 떨어지는 동작을 보이게 된다. [아래그림 참조]
위와같이 설정된 후에 Play 버튼을 눌러보면 위의 큐브가 떨어지면서 아래의 큐브와 충돌하고 다시 바닥으로 굴러 떨어지는 동작을 보게 된다. 이 때 위의 큐브와 아래의 큐브의 위치가 너무 일치하게 되면 굴러 떨어지는 동작은 볼 수 없기 때문에 실행 테스트하기 전에 위의 큐브의 위치를 약간 어긋나게 한 후에 실행하면 좀더 실감나는 동작을 볼 수 있다. 아래의 그림은 Game 뷰만 캡쳐한 것이다.
대포를 발사하면 포탄이 날아가서 어떤 물체와 충돌하는 부분을 작성하려고 한다. 대포 대신 실린더를, 포탄 대신 구를 사용해서 핵심적인 부분에 집중하려고 한다. 우선 Scene 뷰에 Plane, Directional Light, Main Camera 만 남기고 모두 제거한 상태에서 실린더를 하나 추가한다.
Cylinder 를 추가할 때는 GameObject > Create Other > Cylinder 항목을 선택하면 되고 포구가 Z축 방향을 바라보며 포탄을 발사할 준비가 되도록 약간 회전을 적용하면 된다. Cylinder 의 길이와 직경도 적절하게 조절한다.
이제 First Person Controller(FPC) 를 Project 뷰의 Standard Assets/Character Controller/ 에서 드래그하여 Scene 뷰에 올리고 Cylinder 의 옆에 위치하도록 조정하고 Hierarchy 뷰에서 First Person Controller 안에 있는 Main Camera 안으로 Cylinder 를 드래그하여 이동한다. 그리고 FPC의 Main Camera에 대포의 포구가 보이도록 Cylinder의 높이를 조절한다.
위에서 구성한 장면을 FPC의 Main Camera 를 통해 보려면 Hierarchy 뷰의 FPC의 Main Camera를 선택하고 Game 뷰 탭을 선택하면 아래처럼 보이게 된다
이제 Play 버튼을 눌러서 마우스로 포구의 방향이 조절되는지 WASD 키로 이동이 가능한지 학인할 수 있다.
Cylinder 안에서 포탄(Sphere)이 발사되는 동작을 구현할 때 주의할 점은 Cylinder와 포탄이 서로 충돌반응을 일으키지 않아야 하기 때문에 Cylinder 에 포함되어 있는 Capsule Collider 를 Inspector 뷰에서 마우스 우측을 눌러 삭제해주어도 된다. 이 경우에는 스크립트에서 포신과 포탄 사이의 충돌반응을 무시하도록 코드를 작성할 필요가 없다. 그러나 여기서는 이러한 원리만 이해하고 실제로 Capsule Collider를 삭제하지 않으려고 한다. 스크립트에서 충돌반응을 무시하도록 할 것이기 때문이다. 참고로 collider를 삭제하면 스크립트에서 collider 에 접근할 때 오류가 발생하므로 둘 중 한가지만 적용해야 한다.
다음에는 포탄으로 사용할 구(Sphere)를 한개만 Scene 뷰에 올리고 Prefab 으로 설정할 순서이다. Prefab 으로 설정된 게임 오브젝트는 실행시에 원하는 수만큼의 인스턴스를 생성하여 장면에 포함할 수 있기 때문이다. 구를 한개 추가한 후 Project 뷰에 Prefab 한개를 생성하는 절차는 다음과 같다
추가한 Prefab 의 이름을 CannonBall 으로 변경하고 Hierarchy 뷰에 있는 Sphere를 드래그하여 비어 있는 CannonBall 프리팹으로 포함시키면 CannonBall의 아이콘이 흰색에서 청색으로 변경된다. 내용을 포함하고 있는 프리팹이라는 것을 표현하는 것이다.
위의 절차를 마치면 Prefab 을 설정이 끝났으므로 Hierarchy 뷰에 있는 Sphere는 삭제한다. Prefab을 설정할 목적으로 Scene 뷰에 올렸기 때문에 이제 필요가 없게 되었다. Project 뷰에 생성된 Prefab이 있으면 프로그램 실행시에 얼마든지 많은 포탄을 장면에 내 보낼 수 있기 때문이다.
다음 순서는 실행시에 CannonBall Prefab을 이용하여 대포의 위치에 포탄을 생성하는 것이다. 다음과 같은 스크립트를 작성하고 Cylinder에 포함시킨다
#pragma strict
var prefab:GameObject;
var fireRate : float = 0.5;
var nextFire : float = 0.0;
function Start () {
}
function Update () {
if(Input.GetButton("Fire1") && Time.time > nextFire) {// left ctrl or mouse left
nextFire = Time.time + fireRate;
var cannonBall:GameObject = Instantiate(prefab, transform.position, transform.rotation) as GameObject;
Physics.IgnoreCollision(cannonBall.collider, collider);
//포신에 해당하는 실린더의 출구는 Y축 방향이며 포신을 앞쪽으로 기울여 놓은 상태임
cannonBall.rigidbody.AddForce(transform.up*1000); // 포탄의 속도와 방향
}
}
스크립트를 드래그하여 Cylinder 에 포함시킨다
위의 스크립트를 Cylinder 에 드래그하여 포함시키고 Hierarchy 뷰에서 Cylinder 를 선택하면 Inspector 뷰에 스크립트 콤포넌트가 나타날 때 스크립트에서 선언한 변수 prefab은 값이 없이 None 으로 표시되어 있다. 그러므로 Project 뷰의 CannonBall 프리팹을 마우스로 드래그하여 inspector 뷰의 prefab 변수에 할당한다. 모든 설정을 마쳤으므로 Play 버튼을 눌러 테스트해본다
Play 버튼을 눌러 지금까지 설정한 내용이 제대로 실행되는지 테스트한다. 왼쪽 CTRL 키나 마우스 왼쪽 버튼을 누르면 아래 그림처럼 포탄이 발사된다.
유니티에서 'Fire1' 이라는 라벨은 Left CTRL, Mouse Left Button 으로 설정되어 있다. 아래의 절차를 따라 가면 확인할 수 있다.