Chapter 2-1. 무기 : 총 구현 1️⃣ (애니메이션, 파티클, 오디오)
카테고리: Unity Lesson 3
태그: Unity Game Engine
인프런에 있는 케이디님의 [유니티 3D] 실전! 생존게임 만들기 - Advanced 강의를 듣고 정리한 필기입니다. 😀
🌜 강의 들으러 가기 Click
Chapter 2. 무기
총 구현
🚖 총 플레이어에게 붙이기
서브 머신건을 들고 있는 팔 모델 프리팹을 씬에 임포트 한다. 이름은 “SubMachineGun1”로 바꿔준다.
- Player
- Main Camera
- Weapon Camera
- Holder (📜HandController.cs, 📜GunController.cs)
- Handle Holder 서브 머신건 트랜스폼을 맞추기 위해 잠깐 비활성화 해두었다.
Hand
(📜Hand.cs)
- Gun Holder
- 빈 게임 오브젝트로 총 오브젝트를 자식으로 두며 총의 트랜스폼을 대신 담당 한다.
- 위치 (0, -0.8, 0), 회전 (0, 90, 0) 👈 기본 팔 붙일 때와 마찬가지로 Y축 90도 회전시켜 줌.
SubMachineGun1
(📜Gun.cs)- 트랜스폼은 원점으로 맞춘다. 부모인
Gun Holder
의 트랜스폼을 변경해 서브 머신건의 트랜스폼은Gun Holder
얘가 담당할 것. - Layer를 "Weapon"으로 설정해준다.
- Weapon Camera가 오로지
SubMachineGun1
만을 촬영할 수 있도록. 그래야 총이 나무나 다른 오브젝트에 파묻히지 않는다.
- Weapon Camera가 오로지
- 트랜스폼은 원점으로 맞춘다. 부모인
- Handle Holder 서브 머신건 트랜스폼을 맞추기 위해 잠깐 비활성화 해두었다.
- Main Camera
Hand 형 무기들은 Handle Holder
의 자식으로 들어 갈 것이다. 원거리형 무기들은 Gun Holder
의 자식으로 들어갈 것이다. 본인들의 트랜스폼은 원점이지만 부모인 땡땡 홀더들이 트랜스폼 값을 대신해서 담당하게끔. 나중에 두 번재 총 종류인 SubMachineGun2
도 추가할 것이다.
📜Gun.cs
위에서 추가한
SubMachineGun1
오브젝트에 붙인다.
나중에 다른 종류의 총 오브젝트들이 추가되면 그 곳에도 붙을 수 있다.
여러 종류의 총들의 공통적인 부분.
📜Hand.cs 와 비슷하게 짜면 된다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Gun : MonoBehaviour
{
/* ✨모든 종류의 총들이 공통적으로 갖고 있는 속성들(멤버 변수들)✨ */
public string gunName; // 총의 이름. 총의 종류가 여러개이기 때문에.
public float range; // 총의 사정 거리. 총마다 사정 거리 다름. 총알이 너무 멀리까지 영원히 날아가면 안되니까.
public float accuracy; // 총의 정확도. 총의 종류마다 정확도가 다름.
public float fireRate; // 연사 속도. 즉 한발과 한발간의 시간 텀. 높으면 높을 수록 연사가 느려짐. 총의 종류마다 다름.
public float reloadTime;// 재장전 속도. 총의 종류마다 다름.
public int damage; // 총의 공격력. 총의 종류마다 다름.
public int reloadBulletCount; // 총의 재장전 개수. 재장전 할 때 몇 발씩 될지. 총의 종류마다 다름.
public int currentBulletCount; // 현재 총 안의 탄창에 남아있는 총알의 개수.
public int maxBulletCount; // 총알을 최대 몇 개까지 소유할 수 있는지.
public int carryBulletCount; // 현재 총 바깥에서 소유하고 있는 총알의 총 개수.
public float retroActionForce; // 반동 세기. 총의 종류마다 다름.
public float retroActionFineSightForce; // 정조준시 반동 세기. 총의 종류마다 다름.
public Vector3 findSightOriginPos; // 정조준시 총이 향할 위치. 정조준 할 때 총의 위치가 변하니까 그 때의 위치!
public Animator anim; // 총의 애니메이션을 재생할 애니메이터 컴포넌트
public ParticleSystem muzzleFlash; // 화염구 이펙트 재생을 담당할 파티클 시스템 컴포넌트
public AudioClip fire_Sound; // 총 발사 소리 오디오 클립
}
아직 할당 안한 것들이 많다. 일단 몇 개만 값을 설정함.
🚖 총 애니메이션
총 애니메이션 만들기
팔 애니메이션 하나를 가지고 프레임 별로 여러개 쪼개어 애니메이션을 만들었던 것처럼 총도 똑같은 방식으로 동작에 따라 프레임 구간을 떼와 애니메이션들을 만들자. 임포트 받은 서브 머신건 1의 3D 모델 파일(lowPoly_arms_SubMachineGun)또한 이미 애니메이션이 내장되어 있어서 이 애니메이션 프레임을 쪼개어서 각 상황에 맞는 애니메이션을 만들어볼 것이다.
- 총 8 개의 애니메이션 파일을 만들었다.
- Idle, Walk, Run
- 👉 한번 재생 되면 계속 재생시킬 것이라서 Loop Time과 Loop Pose 를 체크해준다.
- 나머지는 반복 필요 없이 한번만 재생 되면 되므로 이 부분을 체크하지 않는다.
- Reload : 재장전 애니메이션
- FindSightMode : 정조준시 애니메이션
- Weapon_Out : 총을 꺼낼 때 애니메이션
- Weapon_In : 총을 꺼낸 후 애니메이션
- Item : 총을 든 상태에서 아이템을 주울 때 애니메이션
발사 할 때 재생될 반동 애니메이션은 없다. 총 자체를 위아래로 움직여서 구현할 것이라서 따로 없다!
총 애니메이션 컨트롤러
- “GunController” 이름의 총 애니메이션 컨트롤러를 만든다.
SubMachineGun1
의 Animator 컴포넌트의 Controller 에 할당- 상태도에 위에서 만든 8 개의 총 관련 애니메이션 파일들을 드래그 해준다.
파라미터는 위와 같이 3 가지를 추가 해준다. Reload만 Trigger고, Walk, Run은 Bool.
Any State
👉Gun0_Reload
- 조건
- 어떤 상태이던 간에
Reload
Trigger가 발동하면 즉시 재장전 애니메이션을 재생한다. - 즉시 재생하게 Hax Exit Time 체크 해제
- 어떤 상태이던 간에
- 조건
Gun0_Reload
👉Gun0_Idle
- 조건
- 재장전 애니메이션이 완전히 끝나면 바로 총들고 가만히 있을 때 애니메이션을 재생한다.
- Has Exit Time 체크
- Exit Time 은 1 로 설정. 재장전 애니메이션을 100퍼센트 재생 다 할 수 있도록.
- Translation Duration은 0으로 설정. 딜레이 없이 즉시 변경.
- 조건
- 나머지 애니메이션은 HandController 에서 짰던 것처럼 똑같이 전이 조건 설정해주면 된다.
- Walk, Run 의 True, False
- Has Exit Time 체크 해제
- Translation Duration은 0.1 으로 설정
📜GunController.cs
Holder
에 붙인다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GunController : MonoBehaviour
{
[SerializeField]
private Gun currentGun; // 현재 들고 있는 총의 📜Gun.cs 가 할당 됨.
private float currentFireRate; // 이 값이 0 보다 큰 동안에는 총알이 발사 되지 않는다. 초기값은 연사 속도인 📜Gun.cs의 fireRate
private AudioSource audioSource; // 발사 소리 재생기
void Update()
{
GunFireRateCalc();
TryFire();
}
private void GunFireRateCalc()
{
if (currentFireRate > 0)
currentFireRate -= Time.deltaTime; // 즉, 1 초에 1 씩 감소시킨다.
}
private void TryFire() // 발사 입력을 받음
{
if(Input.GetButton("Fire1") && currentFireRate <= 0)
{
Fire();
}
}
private void Fire() // 발사를 위한 과정
{
currentFireRate = currentGun.fireRate;
Shoot();
}
private void Shoot() // 실제 발사 되는 과정
{
Debug.Log("총알 발사 함");
}
}
currentFireRate
- 단발로 여러번 쏠 때, 그 한발 한발간의 텀이 길 수록 연사 속도가 낮은 것이다.
- 📜Gun.cs 에서 연사 속도(한발 한발 사이의 텀)인
fireRate
값이 0.2 이라고 예를 들어 보면,currentFireRate = fireRate
이렇게currentFireRate
은 0.2 에서 시작하고, 이currentFireRate
를 1 초마다 1 씩 감소 시킨다.currentFireRate
가 0 보다 클 때까진 발사를 못하게 한다.- 따라서 이 총은 한번 발사한 후 0.2초 동안은 발사를 못하는 것과 같다! 연사 속도를 0.2라고 볼 수 있다.
- 매 프레임마다
- GunFireRateCalc()
- 👉
currentFireRate
을 Time.deltaTime 만큼 감소시킨다. (즉, 1초 동안 1씩 감소하는 것과 마찬가지)
- 👉
- TryFire()
- 👉발사해도 되는 상황인지를 검사한다.
- 마우스 좌클 입력이 들어왔는지 검사
- 그리고
currentFireRate
가 0 이하인지를 검사한다. - 둘 다 만족한다면 Fire()를 실행한다.
- Fire()
- 👉 발사를 위한 과정
- 이제 발사를 곧 바로 할 것이니
currentFireRate
을 다시 📜Gun.cs의fireRate
값으로 초기화 해야 한다.currentFireRate
값은fireRate
에서 시작하여 다시 매 프레임마다 Time.deltaTime 만큼 감소되며, 이 값이 0 이하로 떨어질 때까진 발사하지 못한다. - 실제 발사를 처리하는 Shoot()을 실행한다.
- Shoot()
- 👉 실제 발사를 처리하는 과정.
- Shoot()
- 이제 발사를 곧 바로 할 것이니
- 👉 발사를 위한 과정
- 👉발사해도 되는 상황인지를 검사한다.
- GunFireRateCalc()
🚖 총 발사시 화염구 이펙트, 파티클 시스템
Hierarchy - 우클 - Create - Effect - Particle System
파티클 시스템 1 : 이펙트 효과
이름은 “MuzzleFlash”
MuzzleFlash
오브젝트의 Transform Scale 을 (0.1, 0.1, 0.1) 로 줄여주었다.- 입자 크기를 줄임.
MuzzleFlash
의 Particle System 컴포넌트 설정 문서 참고- Duration 은 1 로 설정한다.
- 파티클 시스템이 실행되는 지속 시간
- Looping 은 체크 해제 한다. 반복 재생 X
- Play On Awake 해제 한다.
- 이걸 체크하면 게임이 시작되자마자 해당 파티클 시스템이 재생된다.
- Start Lifetime 을 0.15 로 설정한다.
- 파티클의 초기 수명.
- 0.15 로 크게 낮춰서 파티클 입자들이 눈깜짝할 새에 사라지는 것을 볼 수 있다. 역시 총 발사 이펙트 효과에 적합할 것 같다!
- Start Speed 를 25 으로 설정한다.
- 해당 방향으로 작용하는 파티클 초기 속도
- Emissions 모듈 👉 한 순간에 빵 터지듯이 동시에 방출될 입자 수. 한발에 동시에 총알 여러발 나가는 총의 이펙트 효과를 구현할 때 좋을 것 같다.
- Rate over Time 은 0 으로 설정한다.
- 시간 단위 당 방출되는 파티클 수
- Bursts 👉 파티클을 생성하는 이벤트
- Count는 15로 설정한다.
- 동시에 한번에 방출되는 파티클 수
- Count는 15로 설정한다.
- Rate over Time 은 0 으로 설정한다.
- Shape 모듈 👉 파티클 입자들이 방출되는 모양을 결정한다. 구라면 구 모양으로 파티클 입자들이 방출되는 식이다.
- Shape를 Sphere 로 설정한다.
- 파티클 입자들이 구 모양을 그리며 모여서 방출된다. 사방으로 발사되긴 하는데 그게 구 형태로 발사되는 식이다. 이 모양 내에서 랜덤한 위치에서 파티클 입자들이 방출된다. 총구는 동그랗기 때문에 역시 총 발사 이펙트 효과에 적합할 것 같다!
- Radius 는 0.01 로 최소로 설정한다. 위에서 설정한 Shpae의 반지름이 된다. 이 반경 내에서 입자들이 태어난다.
- 총구 에서만 파티클 효과를 줄 것이기 때문에
- Shape를 Sphere 로 설정한다.
- Color Over Lifetime 모듈 👉 체크. 수명 주기에 따라 파티클의 색깔과 투명도가 어떻게 변하는지를 설정할 수 있다.
- 저 직사각형 가로 길이가 파티클 입자의 전체 수명 주기이다.
- 우클로 섹션을 추가할 수 있는데, 이 섹션들을 누르면 섹션이 위치한 주기의 구간 별로 색상 혹은 투명도를 다르게 지정할 수 있다.
- 위의 섹션 👉 투명도
- 아래 섹션 👉 색상
- 파티클이 점점 노래지다가 중간즈음부터 점점 투명해져 자연스럽게 수명을 다하는 컬러를 나타냈다.
- 1 번 섹션의 투명도를 256으로 한 후 수명 주기의 중간에 위치하게 하고 2 번 섹션의 투명도를 0 으로 한 후 수명 끝에 위치하게 하면 수명의 중간까진 불투명했다가 중간 이후부턴 점점 투명해지게 만들 수 있다.
- 3, 4 번 섹션의 색상을 노란색으로 추가해서 수명에서 3,4 번 주변 주기 땐 노랗게 변하게 할 수 있다.
- Size Over LifeTime 모듈 👉 체크. 수명 주기에 따라 파티클의 크기가 어떻게 변하는지도 설정할 수 있다.
- 사이즈가 처음엔 최대이다가 수명 주기 동안 점점 곡선을 그리는 형태로 작아지고 사라진다.
- Renderer 모듈 👉 파티클의 이미지나 메시가 어떻게 변환되고 응영처리 되고 덮어 쓰여지는지를 결정한다. 총알 피격 효과처럼 파티클 입자들을 동그랗게 말고 날카롭게 만들어 보자
- Render Mode 를 Stretched Billboard 로 설정한다.
- Render Mode 는 렌더링 된 이미지가 생성되는 방식이다.
- Stretched Billboard 로 설정하면 파티클은 항상 카메라를 향하지만 다양한 Scale 이 적용 된다.
- Camera Scale 은 0 으로
- Speed Scale 은 -0.2 로
- 속도에 비례하여 파티클이 뻗어진다.
- 그냥 0.2 양수로 설정하면 바깥에서 안으로 들어오는 방향이더라.. -0.2 음수로 설정하면 안에서 바깥으로 방향이 반전되서 더 자연스럽다.
- Length Scale 은 0 으로 설정한다.
- Stretched Billboard 로 설정하면 파티클은 항상 카메라를 향하지만 다양한 Scale 이 적용 된다.
- Render Mode 는 렌더링 된 이미지가 생성되는 방식이다.
- Render Mode 를 Stretched Billboard 로 설정한다.
- Texture Sheet Animation 모듈 👉 파티클 입자에 텍스처 또는 애니메이션을 넣을 수 있다!
- Grid 모드 : 일반 적인 입자
- Sprite 모드 : 특정 Sprite 이미지로 대체
- 인스펙터에서 파티클 입자에 입힐 이미지 파일의 Texture Type을 Sprite(2D and UI)로 바꿔준 후 이 미지 파일을 할당해 준다.
- Sprite 에 맞게 입자의 Material도 바꿔주는게 자연스럽다. Renderer 모듈의 Material을 “Sprites-Default” 로 바꿔준다. (스프라이트에 맞는 Material)
- Duration 은 1 로 설정한다.
파티클 시스템 2 : 화염 이펙트 효과
편리하게 위의 Particle System
을 복사하여 만든다. 번쩍 하는 화염 이펙트 효과를 구현함. 이름은 “MuzzleFlash_inner”
- 트랜스폼 Scale 은 (1, 1, 1)로 설정.
- Start Speed 를 0 으로 설정.
- Emissions - Bursts - Count 를 1 로 설정.
- 입자 하나만 생성 및 방출
- Textrue Sheet Animation 체크 해제
- Renderer - Render Mode - Billboard 설정
- Renderer - Material 은 다시 “Default-Particle” 기본 머테리얼로.
- 나머지는 “MuzzleFlash”과 동일
“MuzzleFlash_inner”를 “MuzzleFlash” 의 자식으로 넣어주니 다음과 같은 이펙트 효과가 완성 되었다.
파티클 시스템 배치
MuzzleFlash - MuzzleFlash_inner 파티클 시스템을 SubMachineGun
의 자식인 Amature
의 자식인 Gun
자식으로 넣어준다. 이제 총을 따라다니게 된다. 파티클 시스템을 총구 쪽에 위치시켜 준다. 마찬가지로 총의 자식이 되었으니 Layer를 “Weapon”으로 해준다.
총을 발사할 때마다 파티클 시스템 재생
우선 📜Gun.cs 에 만들어 둔 MuzzleFlash
파티클 시스템을 muzzleflash
변수에 할당한다.
📜GunController.cs
private void Shoot()
{
currentGun.muzzleFlash.Play(); // ✨✨
Debug.Log("총알 발사 함");
}
🚖 총 발사 소리 재생
📜GunController.cs
void Start()
{
audioSource = GetComponent<AudioSource>();
}
private void Shoot() // 실제 발사 되는 과정
{
PlaySE(currentGun.fire_Sound);
currentGun.muzzleFlash.Play();
Debug.Log("총알 발사 함");
}
private void PlaySE(AudioClip _clip) // 발사 소리 재생
{
audioSource.clip = _clip; // 오디오 클립 할당
audioSource.Play(); // 오디오 재생
}
위와 같이 함수를 추가해주고 이 스크립트가 붙어 있는 Holder
에 Audio Source 컴포넌트를 추가한다.
SubMachineGun1
의 📜Gun.cs 의 fire_Sound
에 발사 소리로 쓸 오디오 클립을 할당한다.
게임 실행 후 발사하면 알아서 Audio Source 컴포넌트의 AudioClip 에 fire_Sound
에 할당했던 오디오 클립이 들어오고 재생이 될 것이다.
🚖 여기까지 스크립트 정리
📜Gun.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Gun : MonoBehaviour
{
/* 모든 종류의 총들이 공통적으로 갖고 있는 속성들(멤버 변수들) */
public string gunName; // 총의 이름. 총의 종류가 여러개이기 때문에.
public float range; // 총의 사정 거리. 총마다 사정 거리 다름. 총알이 너무 멀리까지 영원히 날아가면 안되니까.
public float accuracy; // 총의 정확도. 총의 종류마다 정확도가 다름.
public float fireRate; // 연사 속도. 즉 한발과 한발간의 시간 텀. 높으면 높을 수록 연사가 느려짐. 총의 종류마다 다름.
public float reloadTime;// 재장전 속도. 총의 종류마다 다름.
public int damage; // 총의 공격력. 총의 종류마다 다름.
public int reloadBulletCount; // 총의 재장전 개수. 재장전 할 때 몇 발씩 될지. 총의 종류마다 다름.
public int currentBulletCount; // 현재 탄창에 남아있는 총알의 개수.
public int maxBulletCount; // 총알을 최대 몇 개까지 소유할 수 있는지.
public int carryBulletCount; // 현재 소유하고 있는 총알의 총 개수.
public float retroActionForce; // 반동 세기. 총의 종류마다 다름.
public float retroActionFineSightForce; // 정조준시 반동 세기. 총의 종류마다 다름.
public Vector3 findSightOriginPos; // 정조준시 총이 향할 위치. 정조준 할 때 총의 위치가 변하니까 그 때의 위치!
public Animator anim; // 총의 애니메이션을 재생할 애니메이터 컴포넌트
public ParticleSystem muzzleFlash; // 화염구 이펙트 재생을 담당할 파티클 시스템 컴포넌트
public AudioClip fire_Sound; // 총 발사 소리 오디오 클립
}
📜GunController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GunController : MonoBehaviour
{
[SerializeField]
private Gun currentGun; // 현재 들고 있는 총. 📜Gun.cs 가 할당 됨.
private float currentFireRate; // 이 값이 0 보다 큰 동안에는 총알이 발사 되지 않는다. 초기값은 연사 속도인 📜Gun.cs의 fireRate
private AudioSource audioSource; // 발사 소리 재생기
void Start()
{
audioSource = GetComponent<AudioSource>();
}
void Update()
{
GunFireRateCalc();
TryFire();
}
private void GunFireRateCalc()
{
if (currentFireRate > 0)
currentFireRate -= Time.deltaTime; // 즉, 1 초에 1 씩 감소시킨다.
}
private void TryFire() // 발사 입력을 받음
{
if(Input.GetButton("Fire1") && currentFireRate <= 0)
{
Fire();
}
}
private void Fire() // 발사를 위한 과정
{
currentFireRate = currentGun.fireRate;
Shoot();
}
private void Shoot() // 실제 발사 되는 과정
{
PlaySE(currentGun.fire_Sound);
currentGun.muzzleFlash.Play();
Debug.Log("총알 발사 함");
}
private void PlaySE(AudioClip _clip) // 발사 소리 재생
{
audioSource.clip = _clip;
audioSource.Play();
}
}
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글 남기기