728x90
아이템 생성
Item Spawner 게임 오브젝트 생성, 스크립트 생성 추가
ItemSpawner.cs 작성
using UnityEngine;
using UnityEngine.AI; // 내비메시 관련 코드
// 주기적으로 아이템을 플레이어 근처에 생성하는 스크립트
public class ItemSpawner : MonoBehaviour
{
public GameObject[] items; // 생성할 아이템
public Transform playerTransform; // 플레이어의 트랜스폼
public float maxDistance = 5f; // 플레이어 위치에서 아이템이 배치될 최대 반경
public float timeBetSpawnMax = 7f; // 최대 시간 간격
public float timeBetSpawnMin = 2f; // 최소 시간 간격
private float timeBetSpawn; // 생성 간격
private float lastSpawnTime; // 마지막 생성 지점
private void Start() {
// 생성 간격과 마지막 생성 시점 초기화
timeBetSpawn = Random.Range(timeBetSpawnMin, timeBetSpawnMax);
lastSpawnTime = 0;
}
// 주기적으로 아이템 생성 처리 실행
private void Update() {
// 현재 시점이 마지막 생성 시점에서 생성 주기 이상 지남
// && 플레이어 캐릭터가 존재함
if (Time.time >= lastSpawnTime + timeBetSpawn && playerTransform != null) {
// 마지막 생성 시간 갱신
lastSpawnTime = Time.time;
// 생성 주기를 랜덤으로 변경
timeBetSpawn = Random.Range(timeBetSpawnMin, timeBetSpawnMax);
// 아이템 생성 실행
Spawn();
}
}
// 실제 아이템 생성 처리
private void Spawn() {
// 플레이어 근처에서 내비메시 위의 랜덤 위치 가져오기
Vector3 spawnPosition = GetRandomPointOnNavMesh(playerTransform.position, maxDistance);
// 바당에서 0.5만큼 위로 올리기
spawnPosition += Vector3.up * 0.5f;
// 아이팀 중 하나를 무작위로 골라 랜덤 위치에 생성
GameObject selectedItem = items[Random.Range(0, items.Length)];
GameObject item = Instantiate(selectedItem, spawnPosition, Quaternion.identity);
// 생성된 아이템을 5초 뒤에 파괴
Destroy(item, 5f);
}
// 내비메시 위의 랜덤한 위치를 반환하는 메서드
// center를 중심으로 distance 반경 안에서의 랜덤한 위치를 찾음
private Vector3 GetRandomPointOnNavMesh(Vector3 center, float distance) {
// center를 중심으로 반지름이 maxDistance인 구 안에서의 랜덤한 위치 하나를 저장
// Random.insideUnitSphere는 반지름이 1인 구 안에서의 랜덤한 한 점을 반환하는 프로퍼티
Vector3 randomPos = Random.insideUnitSphere * distance + center;
// 내비메시 샘플링의 결과 정보를 저장하는 변수
NavMeshHit hit;
// maxDistance 반경 안에서 randomPos에 가장 가까운 내비메시 위의 한 점을 찾음
NavMesh.SamplePosition(randomPos, out hit, distance, NavMesh.AllAreas);
// 찾은 점 반환
return hit.position;
}
}
- Time.time : 시작 후 실행 시간
Time.deltaTime : 다음 Update까지의 시간 간격
- Quaternion.identity : 오일러각(0,0,0) 회전에 대응. 회전 필요없을 때 얘 씀!
- Random.insideUnitSphere 프로퍼티 : 반지름이 1유닛인 구 내부의 한 점을 반환함
- Random.insideUnitSphere * distance + center
= 위치가 center이며 반지름이 distance인 구 내부의 랜덤한 한 점을 선택하겠다
- Random.insideUnitSphere * distance + center
- NavMesh.SamplePosition : 내비메시 샘플링
- 특정 반경 내부에서 어떤 위치와 가장 가까운 내비메시 위의 한 점을 찾는 처리
- randomPos와 가장 가까운 내비메시 위의 한 점을 찾음!
- 내비메시 샘플링의 실행 결과는 레이캐스트처럼 별개의 정보 저장용 변수에 할당.
내비메시 샘플링 정보를 저장할 NavMeshHit 타입의 변수 hit을 선언해놓았음
- NavMeshHit hit;
- out : 두 개 이상의 결과값을 낼 때 씀. 출력전용 매개변수
Item Spawner 스크립트에 할당해주자
아이템들
AmmpPack 프리팹에 AmmoPack.cs, Rotator.cs(생성 후) 할당
Rotator.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotator : MonoBehaviour
{
public float rotationSpeed = 60f; // 회전 속도
private void Update() {
transform.Rotate(0f, rotationSpeed * Time.deltaTime, 0f);
}
}
AmmoPack.cs
using UnityEngine;
public class AmmoPack : MonoBehaviour, IItem
{
public int ammo = 30; // 충전할 탄알 수
public void Use(GameObject target)
{
// 전달받은 게임 오브젝트로부터 PlayerShooter 컴포넌트 가져오기 시도
PlayerShooter playerShooter = target.GetComponent<PlayerShooter>();
// PlayerShooter 컴포넌트가 있으며 총 오브젝트가 존재하면
if (playerShooter != null && playerShooter.gun != null)
{
// 총의 남은 탄알 수를 ammo만큼 더함
playerShooter.gun.ammoRemain += ammo;
}
// 사용되었으므로 자신을 파괴
Destroy(gameObject);
}
}
Coin.cs
using UnityEngine;
// 게임 점수를 증가시키는 아이템
public class Coin : MonoBehaviour, IItem
{
public int score = 200; // 증가할 점수
public void Use(GameObject target) {
// 게임 매니저에 접근해 점수 추가
GameManager.instance.AddScore(score);
// 사용되었으므로 자신을 파괴
Destroy(gameObject);
}
}
HealthPack.cs
using UnityEngine;
// 체력을 회복하는 아이템
public class HealthPack : MonoBehaviour, IItem
{
public float health = 50; // 체력을 회복할 수치
public void Use(GameObject target)
{
// 전달받은 게임 오브젝트로부터 LivingEntity 컴포넌트 가져오기 시도
LivingEntity life = target.GetComponent<LivingEntity>();
// LivingEntity 컴포넌트가 있다면
if (life != null)
{
// 체력 회복 실행
life.RestoreHealth(health);
}
// 사용되었으므로 자신을 파괴
Destroy(gameObject);
}
}
아이템이 뜬다!
- 포스트 프로세싱 (Post Precessing) : 후처리
- 게임 화면이 최종 출력되기 전에 카메라의 이미지 버퍼에 삽입하는 추가 처리
- 대부분 포스트 프로세싱 연산은 렌더링 파이프라인의 주요 과정에서 적용되지 않고 마지막 부분에 적용됨
- 모바일 앱의 카메라 필터를 사용하는 것과 같음. 사진을 촬영하는 동안에 적용되는 것이 아니라 사진 촬영 후 적용되기 때문
- 렌더링 파이프라인 : 전체적으로 그려지는 것
- 색감 조정 : DI 색보정 처리 개념
에셋스토어에도 있당~!
포스트 프로세싱을 적용하기 전에 최선의 품질을 얻기 위해 카메라의 렌더 설정을 변경하자
이 렌더 설정은 렌더링 파이프라인과는 다름
- 렌더링 파이프라인 : 각각의 오브젝트에서 쉐이더 부분에 함
- 카메라의 렌더 설정 : 카메라에 새로운 필터를 추가하는 것. 카메라가 처리하는 렌더 영역에 추가하는 거라고 생각
Main Camera 의 Camera
- 렌더링 경로 (Rendering Path) : 렌더링이 처리되는 순서와 방법을 결정하는 옵션
- 기본값 - Use Graphics Settings : 프로젝트 설정에 맞춰 자동으로 렌더링 경로를 결정
- 일반적으로 포워드 렌더링 (Forward Rendering) 옵션으로설정
- 포워드 렌더링 : 성능이 가볍지만 라이팅 표현이 실제보다 간략화되고 왜곡됨
- 각각의 오브젝트를 그릴 때마다 해당 오브젝트에 영향을 주는 모든 라이팅도 함께 계산하는 전통적인 방식
- 하나의 게임 오브젝트에 대해 최대 4개의 광원만 제대로 개별 연산함. 나머지 '중요하지 않은' 광원과 라이팅 효과는 부하를 줄이기 위해 합쳐서 한 번에 연산함. 따라서 라이팅 효과가 실제와 다르게 표현될 수 있음
- 메모리 사용량이 적고 저사양에서도 비교적 잘 동작
- 연산 속도 느림
- 오브젝트와 광원이 움직이거나 수가 많아질수록 연산량이 급증하여 사용하기 힘듦
- 포워드 렌더링 : 성능이 가볍지만 라이팅 표현이 실제보다 간략화되고 왜곡됨
- 우리는 디퍼드 셰이딩(Deferred Shading) 으로 바꿔서 빛을 온전히 표현
- 디퍼드 셰이딩 : 라이팅 연산을 미뤄서(deferred) 실행하는 방식
- 디퍼드 셰이딩의 첫 번째 패스에서는 오브젝트의 메시를 그리되 라이팅을 계산하거나 색을 채우지 않음. 대신 오브젝트의 여러 정보를 종류별로 버퍼에 저장함.
두 번째 패스의 정보를 활용해 라이팅을 계산하고 최종 컬러를 결정함 - 개수 제한 없이 광원 표현. 모든 광원의 효과가 올바르게 표현됨
- 단, MSAA 같은 일부 안티앨리어싱(계단 현상 제거) 설정을 제대로 지원하지 않음. 그래서 MSAA 설정을 Off 했음
- 디퍼드 셰이딩의 첫 번째 패스에서는 오브젝트의 메시를 그리되 라이팅을 계산하거나 색을 채우지 않음. 대신 오브젝트의 여러 정보를 종류별로 버퍼에 저장함.
- 디퍼드 셰이딩 : 라이팅 연산을 미뤄서(deferred) 실행하는 방식
포스트 프로세싱을 적용하자
포스트 프로세스 레이어 컴포넌트 추가
레이어는 여기서 추가
- 포스트 프로세스 레이어는 포스트 프로세싱 볼륨을 감지하고 포스트 프로세싱 볼륨으로부터 설정을 얻어와 카메라에 적용함.
씬의 모든 게임 오브젝트에 대해 포스트 프로세싱 볼륨을 찾으려 하면 성능에 악영향이므로
특정 레이어에 대해서만 볼륨을 감지하도록 레이어 추가해주었음 - 안티앨리어싱 모드(Antialiasing Mode) : 물체의 경계선을 매끄럽게 그리도록 계단 현상을 제거
- FXAA(Fast Approximate Anti-Aliasing) : 전반적인 품질은 높지 않지만 성능 저하가 가장 적고 연산이 빠른 방식
포스트 프로세스 볼륨을 추가해보자
레이어를 PostProcessing으로 해줌
- 근데 딱 저 초록 부분만 후처리가 되는 것임
- 원래 포스트 프로세스 볼륨은 트리거 콜라이더와 함께 사용함. 포스트 프로세스 볼륨의 콜라이더와 포스트 프로세스 레이어의 Trigger 필드에 할당된 게임 오브젝트의 위치가 겹치면 해당 포스트 프로세스 볼륨의 효과가 포스트 프로세스 레이어 컴포넌트를 거쳐 카메라에 적용
- 하지만 우리는 일괄적으로 효과 적용하고 싶음 -> is Global 체크! = 게임의 전체적인 후처리~~!
Profile : 즐겨찾기라고 생각
Global Profile 할당
와~~~
'Hello, World! > Unity' 카테고리의 다른 글
유니티 3D 좀비 서바이벌 게임 만들자 (19) (0) | 2022.06.02 |
---|---|
유니티에서 VR 만들자 (GoogleVR과 안드로이드) (0) | 2022.06.02 |
유니티 3D 좀비 서바이벌 게임 만들자 (17) (0) | 2022.06.01 |
유니티 3D 좀비 서바이벌 게임 만들자 (16) (0) | 2022.06.01 |
유니티 3D 좀비 서바이벌 게임 만들자 (15) (0) | 2022.06.01 |
댓글