7. 들어가기 전에
이 장에서는 앞 장에서 만든 플레이어를 노리는 탄알을 만든다. 탄알 게임 오브젝트를 완성하고, 탄알 생성기로 탄알을 주기적으로 생성한다. 또한 탄알과 플레이어 사이의 충돌을 감지하는 방법을 배운다.
레트로의 유니티 게임 프로그래밍 에센스 | 이제민 - 교보문고
레트로의 유니티 게임 프로그래밍 에센스 | 이제민 - 교보문고
레트로의 유니티 게임 프로그래밍 에센스 | 독자분들로부터 수많은 찬사를 받았던 유니티 대표 도서 『소문난 명강의:레트로의 유니티 게임 프로그래밍 에센스』가 개정판으로 돌아왔습니다!
product.kyobobook.co.kr
7.1 탄알 게임 오브젝트 준비
탄알 게임 오브젝트를 만들고 필요한 컴포넌트를 추가한다. 탄알은 생성된 후 앞쪽 방향으로 일정 속도로 날아간다. 또한 어떤 게임 오브젝트와 충돌했을 때 충돌한 게임 오브젝트가 플레이어라면 해당 게임 오브젝트를 파괴한다.
7.1.1 Bullet 게임 오브젝트 만들기
탄알이 될 Bullet 게임 오브젝트를 만든다.
1. Bullet 게임 오브젝트 생성
- 구(Sphere) 게임 오브젝트 생성(하이어라키 창에서 + > 3D Object > Sphere)
- Sphere 게임 오브젝트의 이름을 Bullet 으로 변경
- Bullet 게임 오브젝트의 위치를 (0, 5, 0), 스케일을 (0.5, 0.5, 0.5) 로 변경
- 하이어라키 창에서 Bullet 더블 클릭 > Bullet 게임 오브젝트가 씬 창에서 포커스 됨

2. Bullet Color 머티리얼 생성
- 프로젝트 창에서 + > Material 클릭
- 생성된 머티리얼의 이름을 Bullet Color 로 변경
- 게임 오브젝트의 컬러를 (255, 0, 0) 으로 변경

3. Bullet 게임 오브젝트를 붉은색으로 변경
- 프로젝트 창의 Bullet Color 머티리얼을 씬 창의 Bullet 게임 오브젝트로 드래그&드롭

7.1.2 리지드바디 컴포넌트 설정하기
탄알이 속도를 가지도록 Bullet 게임 오브젝트에 리지드바디 컴포넌트를 추가한다. 리지드바디 컴포넌트의 중력 사용 필드를 체크 해제하여 중력을 무시한다(총알이 바닥으로 안 떨어지게 하기 위함)
1. 리지드바디 컴포넌트 추가 및 설정
- 하이어라키 창에서 Bullet 게임 오브젝트 선택
- Rigidbody 컴포넌트 추가
- Rigidbody 컴포넌트의 Use Gravity 체크 해제

7.1.3 콜라이더 설정하기
Bullet 게임 오브젝트에는 구 콜라이더(Sphere Collider)가 추가되어 있어 물리적인 표면이 존재한다. 따라서 게임 오브젝트가 콜라이더를 가진 다른 게임 오브젝트와 충돌하면 튕겨나갈 수 있다.
탄알이 다른 탄알에 충돌했을 때 튕겨나가지 않고 그냥 통과하도록 만들 것이다. 이때 트리거(Trigger)로 설정된 콜라이더를 사용한다.
트리거 콜라이더란?
트리거 콜라이더는 충돌한 물체를 밀어내는 물리적인 표면이 없다. 그래서 트리거 콜라이더는 다른 일반 콜라이더와 겹치거나 서로를 뚫고 지나갈 수 있지만 충돌 자체는 감지한다. 따라서 트리거 콜라이더는 충돌이 감지되었을 때 어떤 기능을 실행하는 방아쇠로 많이 사용한다.
1. Bullet 게임 오브젝트의 콜라이더를 트리거로 만들기
- Sphere Collider 컴포넌트의 Is Trigger 체크

7.1.4 Bullet 을 프리팹으로 만들기
스크립트를 제외한 Bullet 게임 오브젝트의 구성이 완료됐다. 탄알 생성기로 Bullet 게임 오브젝트를 게임 도중 실시간으로 복제 생성할 것이다.
탄알 생성기 입장에서는 생성할 Bullet 게임 오브젝트의 원본 게임 오브젝트가 필요하다. 따라서 게임 Bullet 게임 오브젝트를 프리팹으로 만든다. 어떤 게임 오브젝트를 프리팹으로 만들려면 해당 게임 오브젝트를 하이어라키 창에서 프로젝트 창으로 드래그&드롭한다.
프리팹이란?
프리팹은 언제든지 재사용할 수 있는 미리 만들어진 게임 오브젝트 에셋(파일)이다. 비슷한 게임 오브젝트를 여러 개 만들 때 매번 다시 설정하는 번거로움을 줄이기 위해 프리팹을 사용한다.
1. Bullet 프리팹 만들기
- Bullet 게임 오브젝트를 하이어라키 창에서 프로젝트 창으로 드래그&드롭

2. Bullet 프리팹에서 Bullet 게임 오브젝트 생성
- 프로젝트 창의 Bullet 프리팹을 하이어라키 창으로 드래그&드롭

3. Bullet(1) 게임 오브젝트 삭제
- 삭제해라

7.2 탄알 스크립트 준비
탄알이 실제로 동작할 수 있도록 Bullet 스크립트를 생성한다.
1. Bullet 스크립트 생성
- C# Script 생성
- 이름을 Bullet 으로 변경
- Bullet 스크립트 열기

7.2.1 Bullet 의 변수
Bullet 스크립트에 필요한 변수는 speed, bulletRigidbody 이다.
1. Bullet 에 변수 선언
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
public float speed = 8f; // 이동 속력
private Rigidbody bulletRigidbody; // 이동에 사용할 리지드바디 컴포넌트
void Start()
{
}
}
7.2.2 탄알 속도 지정하기
스크립트가 활성화될 때 실행될 Start() 메서드에서는 Bullet 게임 오브젝트의 리지드바디 컴포넌트를 bulletRigidbody 에 할당해야 한다. 그리고 bulletRigidbody.velocity 로 탄알의 속도를 변경한다.
1. Start() 메서드에서 탄알 속도 지정하기
이제 탄알은 앞쪽으로 초당 speed 만큼 이동한다.
Transform 타입의 변수 transform 은 자신의 게임 오브젝트의 트랜스폼 컴포넌트로 바로 접근하는 변수이다. 이는 모든 게임 오브젝트가 하나씩 가지고 있도록 강제되어 있다.
트랜스폼 컴포넌트는 위치, 크기, 회전에 대한 여러 가지 편의 기능을 제공한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
public float speed = 8f; // 이동 속력
private Rigidbody bulletRigidbody; // 이동에 사용할 리지드바디 컴포넌트
void Start()
{
// 게임 오브젝트에서 Rigidbody 컴포넌트 찾아와서 할당
bulletRigidbody = GetComponent<Rigidbody>();
// 리지드바디의 속도 = 앞쪽 방향 * 이동 속력
bulletRigidbody.velocity = transform.forward * speed;
}
}

7.2.3 탄알 자동 파괴하기
게임 도중에는 탄알이 굉장히 많이 생성된다. 플레이어가 피한 탄알은 게임 화면 바깥으로 영원히 움직이면서 게임 화면에서는 보이지 않지만 씬에 계속 남게 된다.
사라지지 않고 화면 밖으로 날아간 탄알 수가 계속 증가하면 컴퓨터 메모리를 엄청나게 낭비한다. 따라서 탄알이 생성된 후 일정 시간이 프르면 탄알이 스스로 자동 파괴되게 한다.
1. 탄알 자동 파괴 기능 추가
Destroy 메서드는 입력한 오브젝트를 파괴한다. gameObject 는 자신의 게임 오브젝트를 가리키는 변수이므로 Destroy(gameObject); 를 실행하면 자신의 게임 오브젝트(여기서는 Bullet 게임 오브젝트) 가 즉시 파괴된다.
Destroy 는 초 단위로 지연시간을 줄 수 있다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
public float speed = 8f; // 이동 속력
private Rigidbody bulletRigidbody; // 이동에 사용할 리지드바디 컴포넌트
void Start()
{
// 게임 오브젝트에서 Rigidbody 컴포넌트 찾아와서 할당
bulletRigidbody = GetComponent<Rigidbody>();
// 리지드바디의 속도 = 앞쪽 방향 * 이동 속력
bulletRigidbody.velocity = transform.forward * speed;
// 3초 뒤에 자신의 게임 오브젝트 파괴
Destroy(gameObject, 3f);
}
}
7.3 탄알의 충돌 처리
플레이어와의 충돌을 감지하는 기능을 작성한다.
7.3.1 충돌 이벤트 메서드
유니티에서 콜라이더를 가진 게임 오브젝트 A와 B가 서로 충돌한 상황에서 둘 다 자신이 충돌했다는 사실을 모른다.
게임 오브젝트는 자신이 충돌한 사실을 스스로 알 수 없고, 대신 충돌했음을 알려주는 메시지가 A와 B에 보내진다. 충돌 메시지를 통해 게임 오브젝트와 해당 게임 오브젝트에 추가된 컴포넌트들은 충돌 사실을 알게 되고 충돌에 대응하는 메서드를 실행한다.
게임 오브젝트와 컴포넌트는 충돌 종류에 따라 OnTriggerEnter 혹은 OnCollisionEnter 메시지를 받는다.
충돌 메시지에는 충돌한 상대방 게임 오브젝트에 대한 정보도 함께 첨부된다. A에는 충돌한 상대방 B 게임 오브젝트의 정보가 전달된다. 메시지 기반 방식 덕분에 우리는 충돌을 어떻게 감지할까 고민하지 않아도 된다. 단지 충돌했을 때 무엇을 실행할지만 결정하면 된다.
1. OnCollision 계열 : 일반 충돌
일반적인 콜라이더를 가진 두 게임 오브젝트가 충돌할 때 자동으로 실행된다. 충돌한 두 콜라이더는 서로 통과하지 않고 밀어낸다.
OnCollision 계열 메서드가 실행될 때는 메서드 입력으로 충돌 관련 정보가 Collision 타입으로 들어온다. Collision 타입은 충돌 관련 정보를 담아두는 단순한 정보 컨테이너이다. 즉, 충돌한 상대방 게임 오브젝트, 충돌 지점, 충돌 표면의 방향 등을 알 수 있다.
- OnCollisionEnter(Collision collision) : 충돌한 순간
- OnCollisionStay(Collision collision) : 충돌하는 동안
- OnCollisionExit(Collision collision) : 충돌했다가 분리되는 순간
2. OnTrigger 계열 : 트리거 충돌
충돌한 두 게임 오브젝트의 콜라이더 중 최소 하나가 트리거 콜라이더라면 자동으로 실행된다. 이 경우 두 게임 오브젝트가 충돌했을 때 서로 그대로 통과한다.
메서드 입력으로 충돌한 상대방 게임 오브젝트의 콜라이더 컴포넌트가 Collider 타입으로 들어온다. Collision 이 아닌 Collider 타입을 입력받는 이유는 트리거 충돌에는 상세한 충돌 정보가 필요 없기 때문이다.
- OnTriggerEnter(Collider other) : 충돌한 순간
- OnTriggerStay(Collider other) : 충돌하는 동안
- OnTriggerExit(Collider other) : 충돌했다가 분리되는 순간
7.3.2 탄알에 충돌 감지 구현
Bullet 게임 오브젝트의 콜라이더 컴포넌트는 Is Trigger 가 체크된 트리거 콜라이더이다. 따라서 충돌 이벤트 메서드로 OnTriggerEnter() 를 작성해야 한다.
1. OnTriggerEnter() 메서드 작성
입력으로 들어오는 other 는 충돌한 상대방 게임 오브젝트의 콜라이더 컴포넌트이다.
먼저 other 을 통해 충돌한 상대방 게임 오브젝트의 태그가 Player 인지 검사한다. 게임 오브젝트나 컴포넌트는 tag 라는 변수를 제공하여 자신의 게임 오브젝트의 태그가 무엇인지 알려준다. 6장에서 Player 게임 오브젝트에 Player 태그를 할당했다. 따라서 충돌한 상대방 게임 오브젝트의 태그 other.tag 가 Player 와 일치하면 상대방 게임 오브젝트는 Player 게임 오브젝트이다.
플레이어 게임 오브젝트가 맞다면 PlayerController 컴포넌트를 가져오고 Die 를 실행한다. 즉, 플레이어가 죽게 된다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
public float speed = 8f; // 이동 속력
private Rigidbody bulletRigidbody; // 이동에 사용할 리지드바디 컴포넌트
void Start()
{
// 게임 오브젝트에서 Rigidbody 컴포넌트 찾아와서 할당
bulletRigidbody = GetComponent<Rigidbody>();
// 리지드바디의 속도 = 앞쪽 방향 * 이동 속력
bulletRigidbody.velocity = transform.forward * speed;
// 3초 뒤에 자신의 게임 오브젝트 파괴
Destroy(gameObject, 3f);
}
// 트리거 충돌 시 자동으로 실행되는 메서드
private void OnTriggerEnter(Collider other)
{
// 충돌한 상대방 게임 오브젝트가 Player 태그를 가진 경우
if (other.tag == "Player")
{
// 상대방 게임 오브젝트에서 PlayerController 컴포넌트 가져오기
PlayerController playerController = GetComponent<PlayerController>();
// 상대방으로부터 PlayerController 컴포넌트를 가져오는 데 성공했다면
if (playerController != null)
{
// 상대방 PlayerController 컼ㅁ포넌트의 Die() 메서드 실행
playerController.Die();
}
}
}
}
7.3.3 완성된 전체 Bullet 스크립트
스크립트를 저장하고 유니티 에디터로 돌아간다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
public float speed = 8f; // 이동 속력
private Rigidbody bulletRigidbody; // 이동에 사용할 리지드바디 컴포넌트
void Start()
{
// 게임 오브젝트에서 Rigidbody 컴포넌트 찾아와서 할당
bulletRigidbody = GetComponent<Rigidbody>();
// 리지드바디의 속도 = 앞쪽 방향 * 이동 속력
bulletRigidbody.velocity = transform.forward * speed;
// 3초 뒤에 자신의 게임 오브젝트 파괴
Destroy(gameObject, 3f);
}
// 트리거 충돌 시 자동으로 실행되는 메서드
private void OnTriggerEnter(Collider other)
{
// 충돌한 상대방 게임 오브젝트가 Player 태그를 가진 경우
if (other.tag == "Player")
{
// 상대방 게임 오브젝트에서 PlayerController 컴포넌트 가져오기
PlayerController playerController = GetComponent<PlayerController>();
// 상대방으로부터 PlayerController 컴포넌트를 가져오는 데 성공했다면
if (playerController != null)
{
// 상대방 PlayerController 컼ㅁ포넌트의 Die() 메서드 실행
playerController.Die();
}
}
}
}
7.3.4 Bullet 게임 오브젝트 완성
완성된 Bullet 스크립트를 Bullet 게임 오브젝트에 컴포넌트로 추가한다. 그리고 수정된 Bullet 게임 오브젝트의 변경 사항을 Bullet 프리팹에 반영한다.
1. Bullet 스크립트 적용하기
- Bullet 스크립트를 드래그&드롭
- Bullet 게임 오브젝트 선택 > 인스펙터 창 상단의 Overrides > Apply All 클릭

2. 씬에 남은 Bullet 게임 오브젝트 삭제
Bullet 프리팹에 변경 사항을 적용햇으니 씬에 있는 Bullet 게임 오브젝트는 지운다. 다음부터는 코드로 Bullet 프리팹에서 실시간으로 Bullet 게임 오브젝트를 생성할 것이기 때문이다.

7.4 탄알 생성기 준비
탄알 생성기 게임 오브젝트는 랜덤한 시간 간격으로 탄알을 생성하고 플레이어를 향해 발사한다. 이들을 게임 월드의 네 방향 끝에 배치한다.
7.4.1 Bullet Spawner 게임 오브젝트 준비
먼저 탄알 생성기가 될 게임 오브젝트를 만들고 배치한다. 탄알 생성기를 만드는데 원기둥 게임 오브젝트를 활용한다.
1. Bullet Spawner 게임 오브젝트 생성
- 생성된 게임 오브젝트의 이름을 Bullet Spawner 로 변경
- 위치를 (8, 1, 0) 으로 변경
- 프로젝트 창의 Bullet Color 머티리얼을 씬 창의 Bullet Spawner 게임 오브젝트로 드래그&드롭


7.5 탄알 생성기 스크립트 만들기
탄알 생성기 Bullet Spawner 게임 오브젝트가 탄알을 생성할 수 있게 하는 BulletSpawner 스크립트를 만든다.
1. BulletSpawner 스크립트 생성
- C# Script 만들고 이름을 BulletSpawner 로 변경
7.5.1 BulletSpawner 의 변수
1. BulletSpawner 의 변수 선언하기
추가된 변수들의 역할
public 변수
- bulletPrefab : 탄알을 생성하는 데 사용할 원본 프리팹
- spawnRateMin : 새 탄알을 생성하는 데 걸리는 시간의 최솟값
- spawnRateMax : 새 탄알을 생성하는 데 걸리는 시간의 최댓값
private 변수
- target : 조준할 대상 게임 오브젝트의 트랜스폼 컴포넌트
- spawnRate : 다음 탄알을 생성할 때까지 기다릴 시간. spawnRateMin 과 spawnRateMax 사이의 랜덤값으로 설정됨.
- timeAfterSpawn : 마지막 탄알 생성 시점부터 흐른 시간을 표시하는 타이머
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletSpawner : MonoBehaviour
{
public GameObject bulletPrefab; // 생성할 탄아르이 원본 프리팹
public float spawnRateMin = 0.5f; // 최소 생성 주기
public float spawnRageMax = 3f; // 최대 생성 주기
private Transform target; // 발사할 대상
private float spawnRate; // 생성 주기
private float timeAfterSpawn; // 최근 생성 시점에서 지난 시간
void Start()
{
}
void Update()
{
}
}
7.5.2 Start() 메서드
먼저 Start() 메서드를 완성한다. Start() 메서드에서는 시간에 관한 변수를 초기화한다. 그리고 탄알으르 발사할 목표가 될 게임 오브젝트의 트랜스폼 컴포넌트를 찾아서 가져온다.
FindObjectOfType 메서드는 꺽쇠 <> 에 어떤 타입을 명시하면 씬에 있는 모든 오브젝트를 검색해서 해당 타입의 오브젝트를 가져온다.
1. Start() 메서드 완성하기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletSpawner : MonoBehaviour
{
public GameObject bulletPrefab; // 생성할 탄아르이 원본 프리팹
public float spawnRateMin = 0.5f; // 최소 생성 주기
public float spawnRageMax = 3f; // 최대 생성 주기
private Transform target; // 발사할 대상
private float spawnRate; // 생성 주기
private float timeAfterSpawn; // 최근 생성 시점에서 지난 시간
void Start()
{
// 최근 생성 이후의누적 시간을 0으로 초기화
timeAfterSpawn = 0f;
// 탄알 생성 간격을 spawnRateMin 과 Max 사이에서 랜덤 지정
spawnRate = Random.Range(spawnRateMin, spawnRageMax);
// PlayerController 컴포넌트를 가진 게임 오브젝트를 찾아 조준 대상으로 설정
target = FindObjectOfType<PlayerController>().transform;
}
void Update()
{
}
}
7.5.3 일정 주기로 실행 반복하기
Update() 메서드에서 탄알을 생성할 것이다. Update 는 1초에 수십번씩 실행된다. 무작정 탄알 생성 코드를 넣으면 탄알이 1초에 수십 개씩 쉴 새 없이 생성된다.
따라서 탄알을 생성하기 전에 마지막으로 탄알을 생성ㅇ한 시점에서 누적된 시간을 저장하는 변수 timeAfterSpawne 을 체크한다.
timeAfterSpawn 값은 시간의 흐름에 맞춰 계속 증가한다. 주기적으로 값을 체크해서 timeAfterSpawn 이 탄알 생성 주기보다 커진 순간 탄알을 생성하고 timeAfterSpawn 을 0으로 리셋한다.
그러면 timeAfterSpawn 값이 0부터 다시 시작되어 증가한다.
7.5.4 Time.deltaTime
초당 프레임은 컴퓨터 성능에 따라 다르다. 따라서 직전 Update 실행과 현재 Update 실행 사이의 시간 간격은 고정되어 있지 않다.
Update() 실행 사이의 시간 간격을 알기 위해 내장 변수 Time.deltaTime 을 사용한다. Time.deltaTime 에는 이전 프레임과 현재 프레임 사이의 시간 간격이 자동으로 할당된다. 즉, 1초에 60 프레임의 속도로 화면을 갱신하는 컴퓨터에서 Time.deltaTime 의 값은 1/60 이다. 마찬가지로 1초에 120 프레임의 속도로 화면을 갱신하는 컴퓨터에서 Time.deltaTime 의 값은 1/120 이다.
따라서 Update() 메서드에서 어떤 변수에 Time.deltaTime 값을 계속 누적하면 특정 시점으로부터 시간이 얼마나 흘렀는지 표현할 수 있다.
7.5.5 Instantiate() 메서드
탄알을 복제 생성 하는 데 Instantiate() 메서드를 사용할 것. 유니티는 게임 도중에 실시간으로 오브젝트를 생성할 때 Instantiate() 메서드를 사용한다.
Instantiate(원본);
Instantiate() 메서드는 원본 오브젝트를 주면 해당 오브젝트를 복제한 오브젝트를 생성한다.
Instantiate 는 인스턴스화로 번역한다. 인스턴스화는 원본에서 복제본을 생성하는 행위를 표현하는 단어이다. 원본으로부터 복제 생성된 오브젝트를 인스턴스라고 부른다.
생성할 탄알의 원본이 될 Bullet 프리팹을 미리 만들어두었다. 그리고 나중에 Bullet 프리팹을 bulletPrefab 변수에 할당할 것이다.
따라서 Instantiate 메서드에 bulletPrefab 을 입력하고 실행하면 실시간으로 Bullet 프리팹을 복제한 새로운 Bullet 게임 오브젝트가 생성된다.
Instantiate(원본, 위치, 회전);
위와 같이 복제본을 생성할 위치와 회전을 지정할 수 있다.
Instantiate(bulletPrefab, transform.position, transform.rotation);
이렇게 하면 bulletPrefab 의 복제본이 탄알 생성기의 위치와 회전으로 생성된다.
7.5.6 Update() 메서드
1. BulletSpawner 스크립트의 Update() 메서드 완성하기
void Update()
{
// timeAfterSpawn 갱신
timeAfterSpawn += Time.deltaTime;
// 최근 생성 시점에서부터 누적된 시간이 생성 주기보다 크거나 같다면
if (timeAfterSpawn >= spawnRate)
{
// 누적된 시간으 ㄹ리셋
timeAfterSpawn = 0f;
// bulletPrefab 의 복제본을
// transform.position 위치와, trnaform.ratation 회전으로 생성
GameObject bullet = Instantiate(bulletPrefab, transform.position, transform.rotation);
// 생성된 bullet 게임 오브젝트의 정면 방향이 target 을 향하도록 회전
bullet.transform.LookAt(target);
// 다음번 생성 간격을 spawnRateMin, spawnRateMax 사이에서 랜덤 지정
spawnRate = Random.Range(spawnRateMin, spawnRageMax);
}
}
7.5.7 완성된 탄알 생성기 스크립트
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletSpawner : MonoBehaviour
{
public GameObject bulletPrefab; // 생성할 탄아르이 원본 프리팹
public float spawnRateMin = 0.5f; // 최소 생성 주기
public float spawnRageMax = 3f; // 최대 생성 주기
private Transform target; // 발사할 대상
private float spawnRate; // 생성 주기
private float timeAfterSpawn; // 최근 생성 시점에서 지난 시간
void Start()
{
// 최근 생성 이후의누적 시간을 0으로 초기화
timeAfterSpawn = 0f;
// 탄알 생성 간격을 spawnRateMin 과 Max 사이에서 랜덤 지정
spawnRate = Random.Range(spawnRateMin, spawnRageMax);
// PlayerController 컴포넌트를 가진 게임 오브젝트를 찾아 조준 대상으로 설정
target = FindObjectOfType<PlayerController>().transform;
}
void Update()
{
// timeAfterSpawn 갱신
timeAfterSpawn += Time.deltaTime;
// 최근 생성 시점에서부터 누적된 시간이 생성 주기보다 크거나 같다면
if (timeAfterSpawn >= spawnRate)
{
// 누적된 시간으 ㄹ리셋
timeAfterSpawn = 0f;
// bulletPrefab 의 복제본을
// transform.position 위치와, trnaform.ratation 회전으로 생성
GameObject bullet = Instantiate(bulletPrefab, transform.position, transform.rotation);
// 생성된 bullet 게임 오브젝트의 정면 방향이 target 을 향하도록 회전
bullet.transform.LookAt(target);
// 다음번 생성 간격을 spawnRateMin, spawnRateMax 사이에서 랜덤 지정
spawnRate = Random.Range(spawnRateMin, spawnRageMax);
}
}
}
7.5.8 BulletSpawner 스크립트 적용하기
완성된 BulletSpawner 스크립트를 BulletSpawner 게임 오브젝트에 컴포넌트로 추가한다.
1. BulletSpawner 스크립트 적용
- BulletSpanwer 스크립트를 BulletSpawner 게임 오브젝트로 드래그&드롭
- 프로젝트 창의 Bullet 프리팹을 인스펙터 창의 Bullet Prefab 필드로 드래그&드롭

7.5.9 탄알 생성기 배치하기
탄알 생성기를 완성했다. 이제 완성된 탄알 생성기를 프리팹으로 만들고, 씬에 탄알 생성기를 여러 개 배치한다.
1. Bullet Spawner 프리팹 만들기
- Bullet Spawner 게임 오브젝트를 프로젝트 창으로 드래그&드롭

2. Bullet Spawner 게임 오브젝트 생성하기
- 프로젝트 창의 Bullet Spawner 프리팹을 하이어라키 창으로 세 번 드래그&드롭
- BulletSpawner (1) 의 위치를 (-8, 1, 0) 으로 변경
- BulletSpawner (2) 의 위치를 (0, 1, 8) 으로 변경
- BulletSpawner (3) 의 위치를 (0, 1, -8) 으로 변경

이제 배치된 네 개의 Bullet Spawner 게임 오브젝트를 모두 Level 게임 오브젝트의 자식으로 넣어 하이어라키 창을 깔끔하게 정리한다. 이는 이후에 Level 게임 오브젝트가 회전할 때 탄알 생성기도 함께 회전하도록 하는 데 필요한 작업이기도 하다.
3. Bullet Spawner 게임 오브젝트를 Level 의 자식으로 넣기

7.6 마치며
이 장에서는 탄알과 탄알 생성기를 만들었다. 유니티에서 충돌을 감지하는 방법을 배우고 탄알과 플레이어 사이의 충돌 감지를 구현했다.