발사 기능 구현
만약 우주선이 총알이나 미사일 같은 무기를 발사하는 기능이 있다면 이것을 어떻게 구현할 지 알아본다.
무기를 발사한다면 다음과 같은 과정이 일반적이다.
- 총알 만들기
- 어떤 방향으로 움직이기
- 일정 시간 후 사라지기
총알 만들기
무기는 게임 도중에 공격할 때 마다 만들어져야 한다.
이렇듯 게임 실행 도중에 스크립트로 게임오브젝트를 만드는 작업을 '런타임 생성(Instantiate a gameobject at runtime)' 이라고 한다.
이런 게임오브젝트를 만들 수 있는 기능이 프리팹(Prefab)이다.
*prefab : Prefabricate의 준말. 사전에 미리 만들어 두다.
즉, 게임오브젝트를 미리 준비해 두었다가 필요할 때 만들거나, 복사해서 대량으로 만들 때 유용하다.
prefab을 사용하려면 먼저 게임오브젝트를 Assets 폴더에 저장하고, 이것을 사용해서 게임오브젝트를 생성한다.
프리팹(Prefab) 만들기
먼저 앞에서 Scripts폴더를 만든것 처럼 프리팹만을 모아서 관리할 수 있도록 Assets 폴더에 Prefabs 폴더를 만든다.
그 다음 '빈 게임오브젝트'를 만들고 이름을 Bullet (총알)이라고 하자.
이렇게 만든 Bullet 게임오브젝트를 프리팹으로 만들고 싶으면 Prefabs폴더로 끌어서 놓는다.
그러면 다음과 같은 프리팹이 만들어진다.
프리팹 설정
Project창의 Bullet 프리팹을 더블클릭하거나 아래 그림에서 Open Prefab(프리팹 열기) 버튼을 클릭하면 설정 모드로 들어갈 수 있다.
Bullet 이미지를 넣기 위해 앞에서 했던것 처럼 Add Component 버튼으로 Sprite Renderer 컴퍼넌트를 추가한다.
Sprite(스프라이트)는 Knob를 선택한다.
Scene탭을 눌러서 씬뷰(화면 보기)로 가면 프리팹이 나타난다.
바로 아래 있는 Color를 빨간색으로 바꾼다.
이렇게 하면 Assets폴더의 Prefabs 폴더에 있는 Bullet(빨간색)과 Hierarchy창에 있는 Bullet (흰색)을 구분할 수 있다.
설정을 완료했으면 Hierarchy창의 뒤로가기 화살표를 클릭해서 Bullet 프리팹에서 빠져나간다.
Bullet과 Ship의 크기도 서로 같으므로 Ship의 크기(Scale)에서 X, Y를 3으로 조정한다.
스크립트로 프리팹 만들기
Bullet프리팹은 Ship에서 발사하기 때문에 ShipControl 스크립트에서 프리팹을 만들어낼 수 있다.
8번줄 : 먼저 게임오브젝트 BulletPrefab 이라는 변수를 public으로 선언한다.
연결된 Ship의 스크립트 컴퍼넌트에 선언한 변수가 나타난다.
위 그림에서는 현재 프리팹으로 사용할 게임오브젝트가 없는 상태(None)다.
설정 버튼을 클릭한 후 Assets에 있는 프리팹 Bullet을 선택한다.
실제로 프리팹을 생성하려면 코드를 작성해야 한다.
33~36번줄 코드를 추가한다.
33번줄: GetKeyDown() 메서드는 설정한 키(Space)가 눌러졌을 때 한번만 체크한다.
35번줄: Instantiate() 메서드는 괄호 안의 인수로 전달된 게임오브젝트를 생성하고 반환한다.
이렇게 생성한 프리팹은 게임오브젝트 Bullet에 저장한다.
참고로 Instantiate()메서드는 Object타입을 반환한다. 그래서 GameObject타입으로 casting(명시적 타입 변환)하고 싶으면 Instantiate(BulletPrefab) as GameObject 로 적으면 된다.
또한 매개변수를 가진 프리팹도 반환 받을 수 있다.
Instantiate(Object gameObject, Vector3 position, Quaternion rotation)
예를 들면 Instantiate(prefab, new Vector3(0,0,0), Quaternion.identity)
*Quaternion.identity : 회전 없음
스크립트를 저장한 후 실행한다.
스페이스바 키를 누를 때마다 프리팹으로 만든 Bullet이 복제(Clone)되어 게임씬에 만들어진다.
그런데 Ship을 움직여 보면 Bullet은 따라 움직이지 않는다.
우주선 위치에 프리팹이 만들어지도록 코드를 수정한다.
36번줄
Bullet의 위치(position)에 Ship의 위치(position)를 저장하라는 코드이다.
이렇게 하면 프리팹이 생성될 때 Ship 위치가 Bullet 위치에 저장되어 만들어질 것이다.
Bullet 프리팹 발사하기
스페이스바 키를 누르면 Bullet 프리팹이 만들어지므로 이제 움직이게 해보자.
게임오브젝트에 속도를 주는 방법은 유니티의 물리엔진이 속도를 제어하는 Rigidbody2D 컴퍼넌트가 대표적이다.
*rigidbody: 뉴턴 역학에서 실제 물체를 모형화 하기 위해 만든, 모양과 크기가 바뀌지 않는 단단한 고체
제일 먼저 해야할 일은 Bullet프리팹에 Rigidbody2D 컴퍼넌트 추가하는 것이다.
Assets--Prefabs 폴더에 있는 Bullet을 더블클릭한 후 Add Component버튼을 사용하여 추가한다.
Rigidbody2D 컴퍼넌트를 추가한 후 Gravity Scale(중력 크기)를 1에서 0으로 수정한다.
중력 크기는 y축 음의 방향으로 힘을 받아 세로축 아래로 움직이기 때문에 여기서는 0으로 한다.
Bullet 프리팹 움직임 스크립트
속도를 제어하는 Rigidbody2D 컴퍼넌트를 추가했으므로 이제 프리팹을 움직이도록 스크립트를 작성한다.
37번줄: Bullet에 GetComponent 메서드를 이용해서 속도를 제어하는 Rigidbody2D컴퍼넌트를 가져온다.
그리고 속도를 주기 위해서는 Rigidbody2D 클래스에 정의되어 있는 AddForce 메서드를 이용하면 된다.
위쪽(세로축 양의 방향)으로 힘을 주기 위해 Vector2.up을 인수로 넣어준다.
GetComponent<Type>( ) 메서드는 GameObject(게임오브젝트)의 컴퍼넌트를 가져올 때 사용한다.
< >괄호는 generic(제네릭)이라고 하는데 여기에 가져올 컴퍼넌트의 타입, 예를 들어 Transform, Rigidbody2D 등을 입력한다. 제네릭에 대해서는 나중에 C# 학습에서 살펴볼 것이다.
component(컴퍼넌트)는 '구성 요소'라는 뜻이므로 get component는 '구성요소를 가져오다'라는 뜻이다.
유니티에서 GetComponent 메서드는 다른 오브젝트(객체)를 가져올 때 사용한다.
스크립트를 저장 후 스페이스바를 누르면 Bullet프리팹이 만들어져 앞으로 조금씩 움직일 것이다.
이제 속도를 높일 수 있는 방법을 알아본다.
앞에서 speed를 만든것 처럼 float타입의 BulletSpeed변수를 public으로 만든다.
이렇게 만든 변수를 Vector2.up에 곱해서 속도를 높여준다.
스크립트를 저장한 후 Inspector창에 생성된 BulletSpeed 값을 100으로 설정하고 테스트 해본다.
Bullet프리팹 사라지게 하기
Bullet프리팹이 생성된 후 일정 시간이 지나서 사라지게 하려면 어떻게 해야 할까?
게임오브젝트를 일정 시간 후 사라지게 하는 스크립트를 만들어서 Bullet프리팹에 연결해 주면 된다.
먼저 Scripts폴더에 Bullet이라는 새 스크립트 파일을 만든다.
Bullet스크립트를 Bullet프리팹에 연결한다.
Assets-- Prefabs폴더에 있는 Bullet프리팹을 더블클릭해서 설정으로 들어간 후 Add Component버튼으로 스크립트를 추가한다.
검색창에 Bu를 입력하면 Bullet스크립트를 찾을 수 있다.
이제 Bullet 스크립트를 열어서 코드를 작성한다.
주석을 삭제하고 새로운 함수를 만들어 완성한 코드는 다음과 같다.
12번줄~15번줄
DestroyBullet 이라는 메서드를 만든다.
이 메서드의 기능은 게임오브젝트를 없애는 것이다.
게임오브젝트를 없애기 위해서는 Destroy( ) 를 사용한다.
*destroy : 파괴하다
Destroy() 메서드는 게임오브젝트를 없앨 때 사용하기 위해 상속받은 클래스에 이미 만들어져 있는 메서드이다.
컴퍼넌트 등과 같은 것도 없앨 수 있다.
괄호 안에는 없앨 대상을 적어 준다.
gameObject 는 Bullet을 나타낸다.
this.gameObject 라고 해도 된다.
this에 대해서는 이후 C# 학습에서 설명한다.
9번줄
게임오브젝트를 파괴하는 기능을 가진 DestroyBullet 메서드를 Start( )메서드에 넣어주면 되지만 여기서는 Bullet을 발사한 후 일정 시간이 지나서 메서드가 작동하도록 해야 한다.
이런 경우에는 Invoke( )메서드를 사용한다.
*invoke : 적용하다
Invoke( ) 메서드는 2개의 인수를 전달해야 한다.
첫번째 인수는 실행할 메서드명을 string(문자열) 형태로 표시한다.
두번째 인수는 메서드 실행을 지연하는 시간을 표시한다.
그러므로 9번줄은 DestroyBullet 메서드를 2초 후에 적용하라는 코드이다.
스크립트를 저장한 후 실행해 보면 만들어진 Bullet프리팹이 2초후에 게임뷰에서 사라지는 것을 확인할 수 있다.
Bullet 프리팹 여러 개 발사하기
스페이스바 키를 한번 눌렀을 때 Bullet을 여러 개 발사하려면 아래 코드처럼 Bullet 수 만큼 코드를 만들어야 한다.
이런 경우에 반복문을 이용해서 코드를 작성하면 다음과 같다.
36번줄
for 반복문의 실행 부분에 Bullet 발사 코드를 넣는다.
조건식에는 카운터로 사용할 변수 i를 만들어 0으로 초기화하고, i가 2보다 작을 때 까지, i값을 1씩 증가한다.
즉, i가 0, 1 일 때 Bullet을 발사하게 된다.
스크립트를 저장한 후 실행해본다.
실행 후 스페이스바 키를 누르면 Bullet 복제(Clone)는 2개 만들어져서 발사된다.
그런데 게임뷰에서는 2개가 함께 이동하는 것을 확인할 수 있다.
이 문제를 해결하려면 어떻게 해야 할까?
39번줄
Vector3 타입의 변수 bulletPosition(총알 위치)을 만들고 현재 위치를 저장한다.
40번줄
세로 축인 y값에 0.5 에 변수i를 곱한 값을 더해서 저장한다.
41번줄
Bullet의 위치(position)에 bulletPosition값을 저장한다.
그러면 처음 만들어지는 Bullet은 y값에 0 , 두번째 Bullet은 y값에 0.5 가 더해져서 위치가 정해진다.
아래와 같이 변수i는 증가하므로 AddForce 메서드에 값을 곱해서 속도를 다르게 하는 방법도 만들 수 있다.
끝.
Wraven...
'취미로 하는 게임코딩_gameCodingAsHobby > 유니티unity로 게임 만들기' 카테고리의 다른 글
유니티15_C#_08_객체 (0) | 2021.02.17 |
---|---|
유니티14_C#_07_클래스와 메서드 (0) | 2021.02.16 |
유니티12_게임 제작 과정_02_Ship Control (0) | 2021.02.10 |
유니티11_게임 제작 과정01_플레이어 만들기 (0) | 2021.02.06 |
유니티10_C#_06_토큰_Token (0) | 2021.01.31 |