Unity - (4) prefab, 생성과 파괴, audio
1. prefab
1.1. 개요
- 자주 쓰게 될 주제 1.
- 클래스처럼 게임 오브젝트계의 클래스의 느낌.
- 설계도를 짜서 복제품을 사용하는 느낌이다.

<일단 저장만 해두면 계속 꺼내 쓸 수 있다>
- 작업을 하더라도 Scene 안에서만 돌 수 있는데 설계도를 만들면 어떤 Scene에서든 사용할 수 있다.
- 공유할 수 있는 작업물의 형태를 만든다는 장점이 있다.
- 게임이란 것은 프로그램이고 재활용 할 것을 파일로 준비해놓고 그것을 활용 가능하게끔 해야 한다.

<뭐든 준비를 안하는 것보단 준비하는 것이 좋다>
- 같은 캐릭터를 어느 Scene에서나 사용할 수 있어야 한다.
- 그런데 계속 복사 붙여넣기 등을 할 순 없는 노릇이다.
- 미리 데이터로 저장하는 것을 사용해야 한다.
1.2. 사용
- 드래그 드랍으로 프로젝트 창에 둔다.

- 이제 Hierachy에 있는 것을 지우고 다시 프로젝트 안에 아까 만든 것을 넣어줄 수 있다.
- 그래서 프리팹을 기반으로 만들어진 것들을 사용한다.
- 게임을 만들 때는 특정 맵을 Prefab, UI 등을 미리 설계된 오브젝트 단위를 재활용 할 수 있도록 하는 것이 프리팹, 게임 오브젝트의 설계도이다.


<이렇게 원본을 수정하면 일괄 적용된다>
- 다른 객체 하나를 고치다가 일괄 적용도 되는데




- 하지만 구분되어 생성하는 것이 중요하다.
- 원본이 훼손되면 안될 경우가 있기 때문.

<그러니 오리지널 본을 수정할 때와 아닐 때를 명확히 하자>
- 이번엔 다른 예제로 만들어보자.


- 이것을 오브젝트에 아까처럼 객체 하나에다가 넣고 일괄 적용하면 원본에도 적용됨을 볼 수 있음.
- 게임 오브젝트에 대한 것을 Prefab으로 관리가 가능하다.


- 이것을 통해 생성을 해볼 것이다. Update로.

- 이런 형식일 것인데,

- 이것으로 생성할 수 있고 엄청나게 많은 수가 생성이 된다.
- 그러나 Destroy를 적용하면

<분명 붙였는데..>

<나노머신 썬>
- 파괴가 안된다
- Player 변수에 어떤 것이 들어가있냐면 Player의 프리팹이 들어가있다.
- 그런데 객체를 없애야 하는데 설계도를 없애봐야 소용이 없다.
- 내부적으로 List를 써야 한다.

- 파괴하는 시점에서는 반대로 게임 오브젝트를 꺼내서 제거해야 한다.

- p를 꺼내오지 않으면 어떤 것을 파괴할지 모르기 때문에 두 줄이 핵심인 셈.
- 실행은 되는데 한가지 걸린다.
- 배열 밖으로 벗어나는 것이 찍히기 때문이다.
- 벗어나면 return을 하면 된다.

2. 생성과 파괴
2.1. 개요
- 자주 쓰게 될 것 2.
- 생성 당시에 옵션을 줄 수 있으나 기억해야 할 함수 이름은 Instantiate와 Destroy이다.
2.2. 사용
- 터렛을 예시로 만들어볼 것이다.

<코가 큰...>
- 프리팹으로까지의 과정을 진행.
- 탄환까지 프리팹으로 진행.

- 다음 스크립트 2개 생성.
- TurretController, BulletController.

- Bullet을 만들었을 때 무엇이 필요할까?

- 이렇게 필요할 것이고 적용을 시키면

- 이제 TurretController로 이동.

- 하지만 충돌 처리를 배우고 나면 이런 느낌은 아닐 것이다.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TurretController : MonoBehaviour
{
// 탄환 소환
// 총구 위치에
[SerializeField] private GameObject _bulletPrefab;
[SerializeField] private Transform _muzzlePoint;
[SerializeField] private float _coolTime;
[SerializeField] private Transform _playerTransform;
[SerializeField] private float _rotateSpeed;
[SerializeField] private float _detectionRange;
//private float _timer;
// 플레이어가 특정 거리 밖에 있을 때 돈다.
// 일정 거리 안이면 플레이어 응시.
private void Update()
{
//_timer += Time.deltaTime;
_coolTime += Time.deltaTime;
float distance = Vector3.Distance(transform.position, _playerTransform.position);
if (distance <= _detectionRange)
{
LookAtPlayer();
if (_coolTime >= 1)
{
SpawnBullet();
_coolTime = 0;
}
}
else
{
RotateTurret();
}
}
private void RotateTurret()
{
transform.Rotate(Vector3.up, _rotateSpeed * Time.deltaTime);
}
private void LookAtPlayer()
{
transform.LookAt(_playerTransform);
}
private void SpawnBullet()
{
// 쿨타임. deltaTime 누적
/*if(_coolTime >= _timer)
return;*/
Instantiate(_bulletPrefab, transform);
/*GameObject bullet = Instantiate(_bulletPrefab);
bullet.transform.position = _muzzlePoint.position;
bullet.transform.rotation = _muzzlePoint.rotation;*/
//_timer = 0;
}
// 격발음
}
3. Audio
3.1. 설명
- 오디오 소스와 리스너로 페어.
- 지금 격발음이 한 번에 들어와야 하는데 음원 파일이라는 것이 나고 유지되는 시간이 필요하고 하나로만 처리하면 끊기고 소리가 나니 여러개가 있을 필요가 있음.

- 터렛이 아닌 총알이 오디오 소스를 갖는 상황으로 생각해볼 것.

- 그럼 소스 코드에서 해보자.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletController : MonoBehaviour
{
// 앞으로 날아가는 것
[SerializeField] private float _speed;
[SerializeField] private float _destroyTime;
[SerializeField] private AudioSource _audioSource;
[SerializeField] private AudioClip _audioClip;
private void Awake()
{
// 오디오 접근
_audioSource = GetComponent<AudioSource>();
_audioSource.loop = false;
_audioSource.Stop();
_audioSource.clip = _audioClip;
_audioSource.Play();
Destroy(gameObject, _destroyTime);
}
private void Update()
{
MoveForward();
}
private void MoveForward()
{
transform.Translate(Vector3.forward * _speed * Time.deltaTime);
}
// 충돌 체크
}
- 오디오 리스너가 없으면 콘솔에서 경고를 띄워준다.
정리
- 힙, 메모리에 축적이 되었다가 관리되는 힙 영역을 청소하는데 Frame이 튈 수 있고 그것을 조심해야 한다.

<이 튄다는 것은 아니지만>
- 생성 파괴를 최소화하는 운용 기법이 필요함.
- 에셋 스토어에서 에셋을 볼 때 빌트인 환경이 되는지를 확인할 것.
- 무료 에셋이라고 해도 .gitignore 단에서 차단되게끔 Import라고 폴더를 별도로 만들어 거기에 에셋들을 두고 이 폴더의 하위들이 git에 올라가지 않도록 관리를 하는 것이 좋을 것이다.
- 에셋들을 패키징하여 별도로 받아서 사용할 것.




