Unity Chapter 6-1. 어메이징 볼링 게임 만들기 : 회전 포신, 포탄
카테고리: Unity Lesson 1
태그: Unity Game Engine
인프런에 있는 이제민님의 레트로의 유니티 C# 게임 프로그래밍 에센스 강의를 듣고 정리한 필기입니다. 😀
🌜 [레트로의 유니티 C# 게임 프로그래밍 에센스] 강의 들으러 가기!
Chapter 6. 어메이징 볼링 게임 만들기
필요한 에셋 임포트
- Window - Assets Store 로 에셋 스토어에 접속
- 아래 에셋 3개를 검색하여 다운로드 받고 Import 해주자.
- 체크되있는 모든 것들을 Import 해주기.
- “Unity Particle Pack” - 파티클
- “Free Music Bundle” - 배경음악
- “8-Bit Sfx” - 효과음
회전 포신 만들기
회전 포신의 모양이 될 오브젝트 만들기
- 큐브 오브젝트를 만든다.
- 얘가 볼을 쏘는 포신의 모양이 될 것!
- 이름은
Ball Barrel Model
- 가로로 길쭉해야 하니 scale 값은 (0.2, 0.2, 2)
- “Barrel”이름의 Material을 만들어 색을 입혀주자
- Box Collider 컴포넌트는 삭제해주자. (Remove Component)
- 얘는 물리적 표면 충돌 처리 필요가 없어서.
Ball Barrel Model
얘는 단순한 3D 그래픽 모양이다.
- 어떤 기능 처리 X
회전 포신을 제어하는 오브젝트 만들기
- 빈 오브젝트를 만든다.
- 회전 포신을 제어하는 기능을 할 것.
- 진짜 볼을 쏘는 기능
- 이름은
Shooter Pivot
- 볼을 쏘는 Pivot 위치의 중심이 될 것.
Ball Barrel Model
을Shooter Pivot
의 자식으로 넣어준다.Shooter Pivot
이 움직이면 이제Ball Barrel Model
도 같이 움직일 것.
- Pivot - Local 상태로 해주고
Shooter Pivot
는 원점 정중앙에 두고Ball Barrel Model
위치만 z축으로 1 이동시켜준다.- pivot은 중앙에 있고 포신 모양은 좀 앞으로 나온 상태.
📜ShooterRotator.cs : 발사버튼을 누르고 있는 동안 포신이 발사 각도를 조절하게
📜ShooterRotator.cs
Shooter Pivot
에 붙여주자.- 포신이 먼저 수평방향으로 회전한 후에 수직방향으로 회전하게 할 것.
- enum을 사용하여 포신의 현재 상태를 4가지로 정의하자.
- Idle : 처음 게임 시작했을 때 모습
- Vertical : 포신이 세로 방향으로 회전하고 있는 상태
- Horizontal : 포신이 가로 방향으로 회전하고 있는 상태
- Ready : 포탄을 쏠 수 있는 상태가 됐을 때
- 수평방향 회전 👉 y 축을 기준으로 회전
- 수직방향 회전 👉 x 축을 기준으로 회전
- 동작 순서
Idle
상태- 마우스좌클 or 왼쪽 Ctrl키 누르는 순간(GetKeyDown)
Horizontal
상태가 된다.- 마우스좌클 or 왼쪽 Ctrl키 누르는 동안(GetKey)
- 수평 방향으로 회전한다.
- y 축을 기준으로 1프레임 당 1/360도 만큼 회전
- 마우스좌클 or 왼쪽 Ctrl키 떼는 순간(GetKeyUp)
Vertical
상태가 된다.- 마우스좌클 or 왼쪽 Ctrl키 누르는 동안(GetKey)
- 수평 방향으로 회전한다.
- x 축을 기준으로 1프레임 당 1/360도 만큼 회전
- 마우스좌클 or 왼쪽 Ctrl키 떼는 순간(GetKeyUp)
Ready
상태가 된다.Redy
state에 대응되는 if 조건문은 없기 때문에Ready
가 되면 대기 상태가 된다.
Ball Barrel Model
는 자식 오브젝트기 때문에Shooter Pivot
가 이렇게 회전하면 `Ball Barrel Model도 같이 회전한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ShooterRotator : MonoBehaviour
{
private enum RotateState
{
Idle, Vertical, Horizontal, Ready
}
private RotateState state = RotateState.Idle; // 1. 처음 시작은 Idle로
public float verticalRotateSpeed = 360f; // 2. 수직방향 회전값 초기값 360도
public float horizontalRotateSpeed = 360f; // 3. 수직방향 회전값 초기값 360도
void Update()
{
if (state == RotateState.Idle)
{
if (Input.GetButtonDown("Fire1")) // 누르는 순간
{
state = RotateState.Horizontal; // Horizontal 상태로 바꾸기
}
}
else if (state == RotateState.Horizontal)
{
if (Input.GetButton("Fire1")) // 누르는 동안
{
transform.Rotate(new Vector3(0, horizontalRotateSpeed * Time.deltaTime, 0));// 수평 방향으로 `회전시키기`
}
else if (Input.GetButtonUp("Fire1")) // 떼는 순간
{
state = RotateState.Vertical; // Vertical 상태로 바꾸기
}
}
else if (state == RotateState.Vertical)
{
if (Input.GetButton("Fire1")) // 누르는 동안
{
transform.Rotate(new Vector3(-verticalRotateSpeed * Time.deltaTime, 0, 0));// 수직 방향으로 `회전시키기`. 뒤로 넘어지는 것처럼 회전 (마이너스)
}
else if (Input.GetButtonUp("Fire1")) // 떼는 순간
{
state = RotateState.Ready; // Ready 상태로 바꾸기
}
}
}
}
- if (Input.GetButtonDown("Fire1"))
- "Fire1"
- 유니티 - Edit - Project Setting - input 에서 확인해 보면
- 현재 “Fire1”은 왼쪽 Ctrl키와 마우스 좌클에 대응된다.
- 누르는 순간(GetKeyDown)
- 누르는 동안(GetKey)
- 떼는 순간(GetKeyUp)
- 참고 포스트
- "Fire1"
- transform.Rotate(new vector3(-verticalRotateSpeed * Time.deltaTime, 0, 0))
- - verticalRotateSpeed
- x축 기준으로 플러스 방향으로 회전하면 앞으로 넘어지는 것 처럼 회전해서 마이너스를 붙여 뒤로 넘어지는 것 처럼 회전하게끔.
- - verticalRotateSpeed
포탄 만들기
enum은 switch문에 쓰기 좋다.
📜ShooterRotator.cs 의 많은 if-else문을 switch-case문으로 변경했다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ShooterRotator : MonoBehaviour
{
private enum RotateState
{
Idle, Vertical, Horizontal, Ready
}
private RotateState state = RotateState.Idle; // 1. 처음 시작은 Idle로
public float verticalRotateSpeed = 360f; // 2. 수직방향 회전값 초기값 360도
public float horizontalRotateSpeed = 360f; // 3. 수직방향 회전값 초기값 360도
void Update()
{
switch(state)
{
case RotateState.Idle:
if (Input.GetButtonDown("Fire1")) // 누르는 순간
{
state = RotateState.Horizontal; // Horizontal 상태로 바꾸기
}
break;
case RotateState.Horizontal:
if (Input.GetButton("Fire1")) // 누르는 동안
{
transform.Rotate(new Vector3(0, horizontalRotateSpeed * Time.deltaTime, 0));// 수평 방향으로 `회전시키기`
}
else if (Input.GetButtonUp("Fire1")) // 떼는 순간
{
state = RotateState.Vertical; // Vertical 상태로 바꾸기
}
break;
case RotateState.Vertical:
if (Input.GetButton("Fire1")) // 누르는 동안
{
transform.Rotate(new Vector3(-verticalRotateSpeed * Time.deltaTime, 0, 0));// 수직 방향으로 `회전시키기`. 뒤로 넘어지는 것처럼 회전 (마이너스)
}
else if (Input.GetButtonUp("Fire1")) // 떼는 순간
{
state = RotateState.Ready; // Ready 상태로 바꾸기
}
break;
case RotateState.Ready:
break;
}
}
}
포탄 오브젝트 만들기
- Sphere 오브젝트를 만들어준다.
- 이름은
Ball
- 이름은
- “Ball”이름의 Material을 만들어 색을 입혀주자
- Sphere Collider 컴포넌트에 is Trigger를 체크해주자.
Ball
은 다른 오브젝트와 부딪치면 튕겨 나간다던지 등등 그런 물리적인 표면 기능은 부여하지 않을 것이다.- 다만 다른 오브젝트와 충돌이 일어나면 어떤 이벤트 처리를 해줄 것이기 때문에 체크!
- Rigidbody 컴포넌트를 추가해준다.
- 물리 기능이 필요하므로!
- 포탄을 발사하면 날아가야 하니까.
- 파티클 사용할 준비
- 다운받아 Import한 “EffectExamples” 폴더에 들어가서 사용할 파티클 Prefab을 Hierarchy창에 옮겨주자.
- /📁EffectExamples/📁Fire&Explosion/📁Prefab
- 🟦PlasmaExplosionEffect 프리팹 을 Heierarchy 창에 가져와 오브젝트로서 씬 상에 실존하게 해주자. (오브젝트 찍어 만들기)
Import 해 온 🟦PlasmaExplosionEffect 프리팹을 수정하여 나만의 프리팹으로 만들기.
- Prefab은 오브젝트를 찍어낼 수 있게 미리 틀처럼 만들어진 오브젝트!
- Assets 폴더에 만들어 놓은 Prefab 을 Hierarchy 창으로 드래그 하면 오브젝트를 찍어낼 수 있다.
- 반대로 Hierarchy 창에서 기존에 실존하던 오브젝트를 Assets 폴더에 옮기면 이 오브젝트를 프리팹으로 만들 수 있다.
- 포탄이 바닥에 떨어지는 순간 빵 터지게 할 것이기 때문에 파티클 효과가 필요하다. Import 해 온 이 파티클을 원하는대로 수정해보자
- 파티클 시스템은 2D 이미지를 랜덤하게 생성해서 특수 효과를 만들어 주는 방식이다.
- 여러 오브젝트(Prefab)이 자식으로 붙어있다. 이 경우엔 4가지 자식이 있음.
- Particle System 컴포넌트에서 Looping 을 체크 해제해준다.
- 파티클 효과는 포탄이 바닥에 떨어지는 그 순간에만 딱 한번 일어나야 하기 때문에 Looping 해제.
PlasmaExplosionEffect
오브젝트 를 비롯한 자식 파티클들까지 전부 선택해준 후 (shift 단축키 이용) Looping을 해제해준다.
- Particle System 컴포넌트에서 Play On Awake 를 체크 해제해준다.
- 파티클 효과 언제 시작될지는 스크립트에서 제어할 것
PlasmaExplosionEffect
오브젝트 를 비롯한 자식 파티클들까지 전부 선택해준 후 (shift 단축키 이용) Play On Awake을 해제해준다.
- 터질 때 효과음을 주자
PlasmaExplosionEffect
오브젝트 에 Audio Source 컴포넌트를 붙여주자.- Audio Clip 부분에 Import 한 mp3 목록 중 “Explosion_00.mp3”을 붙여주도록 하자. (오른쪽에 조그만 동그라미 버튼을 누르면 mp3파일 목록중에서 선택 가능)
- Play On Awake 은 체크 해제 해주자. 재생 되는 시기는 스크립트에서 제어할 것. 참고로 얘를 체크하면 오브젝트가 생성 되자마자 바로 재생한다.
- /📁Assets 에 📁Prefabs 폴더를 새로 만들어 Hierarchy 창에 있는
PlasmaExplosionEffect
오브젝트 을 드래그 앤 드롭 하여 🟦PlasmaExplosionEffect 프리팹 으로 만들어주자.- 사용하는 프리팹은 폴더에 따로 만들어 관리하자. (Original로 드래그 앤 드롭)
- 1 ~ 2까지 수정해 만든 오브젝트를 다시금 *프리팹*으로 만든 것이다.
- 수정한 현재 씬 상에서의 기존
PlasmaExplosionEffect
오브젝트는 삭제해주자.
- 새로 수정하여 만든 🟦PlasmaExplosionEffect 프리팹 을 Hierarchy창으로 드래그 하여
Ball
오브젝트의 자식 오브젝트 로 넣어 주자. (PlasmaExplosionEffect
오브젝트 를 만듬)- 위치는 0, 0, 0으로
Ball
의 위치와 같게 Ball
의 자식이니까Ball
과 함께 졸졸 따라다닐 것.- 그러다가
Ball
이 터지는 자리에서 파티클 효과와 효과음을 재생시킬 것.
- 위치는 0, 0, 0으로
📜Ball.cs
- 📜Ball.cs을
Ball
오브젝트에 붙여주자. - 발사 할 때마다
Ball
오브젝트를 찍어낼 수 있도록Ball
오브젝트를 Prefab으로 만들어 주자.- /📁Assets/📁Prefabs 로 드래그
- 3D Object Plane 오브젝트를 만들어 바닥을 만들어 주자.
- 위치는 원점
- Material로 색깔 주기
- sclae은 (10, 10, 10)
📜Ball.cs 의 역할
Ball
오브젝트가 죽는 순간 자식인PlasmaExplosionEffect
오브젝트(파티클)을 생성하고 죽는다.Ball
오브젝트 주변의 오브젝트들(프롭)도 같이 파괴해야 한다. (👉 다음 포스팅에서 구현)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Ball : MonoBehaviour
{
// ParticleSystem 컴포넌트와 AudioSource 컴포넌트가 붙어 있는 `PlasmaExplosionEffect` 오브젝트를 이 2개의 슬롯에 드래그 앤 드롭 해줄 것.
public ParticleSystem explosionParticle;
public AudioSource explosionAudio;
public float maxDamage = 100f; // 주변에 뿌릴 수 있는 최대의 데미지. 100으로 설정.
public float explosionForce = 1000f; // 폭발 반경 내로 주변에 뿌리는 힘. 1000으로 설정.
public float lifeTime = 10f; // 볼의 수명. 10초 이상 파괴가 안되면 스스로 파괴하게끔 할 것이다. (맵 밖, 버그 등으로 볼이 파괴가 안될 때 파괴해주려고)
public float explosionRadius = 20f; // 폭발 반경
void Start()
{
Destroy(gameObject, lifeTime); // 자기 자신을 10초 뒤에 파괴하게끔
}
private void OnTriggerEnter(Collider other) // Is Trigger가 체크된 `Trigger`인 Collider와 충돌할 때 자동으로 실행된다. other는 충돌한 상대방.
{
explosionParticle.transform.parent = null; // PlasmaExplosionEffect 오브젝트의 부모를 없애버림
explosionParticle.Play(); // 파티클 효과 재생 (Particle System)
explosionAudio.Play(); // 효과음 재생 (Audio Source)
Destroy(explosionParticle.gameObject, explosionParticle.duration); // explosionParticle가 참조하는 gameObject 파괴
Destroy(gameObject); // 자기 자신(Ball) 파괴
}
}
- 변수
- explosionParticle
- ParticleSystem 컴포넌트가 붙어 있는
PlasmaExplosionEffect
오브젝트를 이 슬롯에 드래그 앤 드롭 해줄 것.
- ParticleSystem 컴포넌트가 붙어 있는
- explosionAudio
- Audio Source 컴포넌트가 붙어 있는
PlasmaExplosionEffect
오브젝트를 이 슬롯에 드래그 앤 드롭 해줄 것.
- Audio Source 컴포넌트가 붙어 있는
- maxDamage
- 주변에 뿌릴 수 있는 최대의 데미지.
- explosionForce
- 폭발 반경 내로 주변에 뿌리는 힘.
- lifeTime
- 볼의 수명.
- 10초 이상 파괴가 안되면 스스로 파괴하게끔 할 것이다.
- 맵 밖, 버그 등으로 볼이 파괴가 안될 때 파괴해주려고
- explosionRadius
- 폭발 반경
- explosionParticle
- 함수
- void Start()
Ball
오브젝트가 생성된 후 10초가 지나면 자기 자신을 파괴.
- onTriggerEnter(Collider other)
- Is Trigger가 체크된
Trigger
인 Collider와 충돌할 때 자동으로 실행된다. - other는 충돌한 상대방.
- 충돌하면 자기 자신(
Ball
오브젝트)을 파괴하고PlasmaExplosionEffect
오브젝트(파티클)를 재생해야 한다.- 그러나 부모(
Ball
)가 파괴되면 자식(PlasmaExplosionEffect
)도 파괴되므로Ball
이 파괴되는 순간PlasmaExplosionEffect
는 부모를 없애야 한다.- explosionParticle.transform.parent = null;
PlasmaExplosionEffect
의 부모를 없애준다.- 부모 자식 관계는 *Transform 컴포넌트*가 관리한다.
PlasmaExplosionEffect
의 Particle System 재생- explosionParticle.Play();
PlasmaExplosionEffect
의 Audio Source 재생- explosionAudio.Play();
PlasmaExplosionEffect
오브젝트 파괴- Destroy(explosionParticle.gameObject, explosionParticle.duration)
- duration : 특수 효과가 재생되는 러닝타임을 Particle System 오브젝트 스스로 알고 있다.
Ball
오브젝트(자기 자신)도 파괴.- Destroy(gameObject)
- 그러나 부모(
- Is Trigger가 체크된
- void Start()
- 이제 explosionParticle 슬롯에
PlasmaExplosionEffect
오브젝트를, explosionAudio 슬롯에PlasmaExplosionEffect
오브젝트를 드래그 앤 드롭으로 붙여주고 실행해보자. - Apply를 눌러서 Assets의 Prefab에도 적용시켜주자.
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글 남기기