강의/Unity

[Unity/2D]뱀서라이크 (언데드 서바이버), 골드메탈 1~17 정리

개발의 피 2024. 6. 28. 22:48

https://youtube.com/playlist?list=PLO-mt5Iu5TeZF8xMHqtT_DhAPKmjF6i3x&si=CdE5wqKi4lrlC0UR

 

유니티 기초 뱀서라이크🧟언데드서바이버

요즘 인기많은 장르인 뱀서라이크를 직접 유니티로 개발해보아요!

www.youtube.com

 

모바일 빌드까지 완료해봤당

빌드과정에서... 내가 최근 apk로 빌드를 못했던 게 내 탓이 아니라 유니티 에디터 잘못인 걸 알게 되었고

고치느라 며칠을 고생했다 🥲

 

처음 사용해본 것 : 애니메이션 오버라이드 컨트롤러, Input System  

 

모바일 캡처화면

 

iOS(아이폰 6s) / Android(갤럭시 s10e) 에 어플 설치하고 실행해본 것!

 


1. 2D 오브젝트 만들기 

01 프로젝트 시작하기

02 에셋 가져오기

03 오브젝트 만들기

- 스프라이트 사전 설정

- 스프라이트 에디터 : 슬라이스 (cell by cell size),

- 개별 스프라이트 이름 변경 (run 0~5, stand 0~4, dead 0~1)

04 컴포넌트 추가하기

- Rigidbody 2D 추가 (gravity = 0)

- Capsule Collider 2D 추가

- 자식 오브젝트 : 그림자 스프라이트 추가 (order in layer : player - 5, shadow - 0)

 

2. 플레이어 이동 구현하기

01 C# 스크립트 만들기

02 키보드 입력 받기

- Input.GetAxis : 보정 o

- Input.GetAxisRaw : 더 명확한 컨트롤

03 물리 이동 방법 (FixedUpdate에서)

- Addforce : 힘을 준다

- velocity : 속도 제어

- movePosition : 위치 이동

04 물리 이동 구현

- 이동 방향 normalized : 입력 벡터 크기 영향 x (일관된 이동 속도 보장)

- Time.fixedDeltaTime : 프레임 속도 상관없이 움직임 일관성 보장

 

2-1. 새로운 인풋시스템 적용 (Input System)

01 패키지 설치 (Input System) : 다양한 디바이스 인풋 쉽게 관리

02 인풋 액션 설정

- Create Action

<Action Maps> : Player (UI)

<Actions> : Move (Look, Fire)

<Action Properties>

- Action Type(인풋 형태) : Value (Button, Pass Through)

- Control Type( 형식) : Vector 2 (Vector3, Stick, Axis ...)

- Interactions(호출 타이밍) : (Hold, Press, Slow Tap, Tap 기존 : 값이 변할 때만 가능)

- Processors(후보정) : Normalize Vector 2 (Invert Vector2 - y 반전, ...)

03 스크립트 적용

- 네임스페이스 추가: UnityEngine.InputSystem

- 기존 Update 삭제

- 사용할 액션 -> OnMove(), 매개변수 : InputValue

- inputVec(Vector2) = value(InputValue).Get<Vector2>();

- 기존 nextVec : normalized x

 

3. 2D 셀 애니메이션 제작하기

01 방향 바라보기

spriter.flipX = inputVec.x < 0

02 애니메이션 - 드래그 드랍으로 생성

- Stand / Run / Dead

03 애니메이터 설정

- 조건 파라미터 : Speed - float / Dead - trigger

- Duration : 부드럽게 전환 -> 2D : 0 or 0.01 (필요 x)

- 즉시 상태 변경 : Has Exit Time 체크 해제

- 반복 필요 x(Dead) : Loop Time 체크 해제

04 코드 - 애니메이터 파라미터

- SetFloat("파라미터 이름", float )

- vector2.magnitude : 벡터의 순수 크기

05 애니메이터 재활용

- Animator Override Controller : 애니메이터 구조 그대로, 애니메이션만 덮어씌움        

         

4. 무한 맵 이동

01 타일 그리기 (타일맵)

Rule Tile : 인접한 타일에 따라 이미지가 정해지는 타일

Output - Random

Tilemap - Line Brush : 처음/끝 클릭하면 자동으로 라인 그려줌

Default Brush - 팔레트, bucket 툴 : 채우기

룰 타일 - Noise 조절 : 원하는 형태 나오도록 랜덤

 

02 재배치 이벤트 준비

플레이어와 거리가 멀어지면 앞으로 재배치

* Tilemap

Tilemap Collider 2D 추가 : 개의 타일마다, Used by Composite 체크

Composite Collider 2D 추가 : 타일마다 나눠진 형태를 하나로 합침, Is Trigger 체크(플레이어랑 충돌 x)

Rigidbody - BodyType : static (움직이면 x)

Tag : 타일맵 - Ground

 

* Area (Player 자식)

Box Collider 2D 추가 : Size - 타일맵과 동일 (20 x 20), Is Trigger 체크

Tag : Area

 

03 재배치 로직 스크립트

* Reposition.cs (Tilemap)

OnTriggerExit2D(매개변수 - 상대방 콜라이더 태그) : 트리거 나갔을 발생

플레이어가 트리거 영역을 벗어날 , 타일맵 위치를 변경

타일맵 - 플레이어 거리 차이 : x축이 크면, 수평 이동 / y축이 크면, 수직 이동

 

* GameManager.cs (GameManager)

static(정적 변수) : 즉시 클래스에서 부를 있음 (= 바로 메모리에 얹음)

싱글톤 인스턴스 설정, 플레이어 참조

 

Increment Snapping(스냅핑 이동) : ctrl + 기즈모 드래그 (설정 값만큼 움직임)

 

04 카메라 설정

Pixel Perfect Camera 컴포넌트 - Pixel Per Unit : 스프라이트에서 사용하는 수치와 맞추기, Reference Resolution(카메라 크기 계산을 위한 참고 해상도)

타일맵 크기, Area 크기, 재배치 거리 : 카메라 크기와 비슷하게

 

Cinemachine 패키지 설치, Virtual Camera 추가(감독 역할) - Follow : 플레이어 할당

 

 

5. 몬스터 만들기

5-1. [몬스터 만들기]몬스터 오브젝트 만들기

- 리지드 바디 : gravity 0, freeze rotation - z 체크

- 스프라이트 렌더러 : 오더 레이어 - 2

- 캡슐 콜라이더 2d

- 애니메이터 컨트롤러

 

5-2. [몬스터 만들기]플레이어 추적 로직

FixedUpdate : 물리 이동 (타겟 = 플레이어 - 위치 차이 구해서, 방향으로 이동)

LateUpdate : x 반전 (타겟 x 값과 비교해서, 작으면 true)

 

5-3. [몬스터 만들기]몬스터 재배치

몬스터가 플레이어에게서 너무 멀어지면 = 카메라에서 보이면

-> 맵의 크기만큼, 플레이어의 이동 방향에 따라 맞은 편에서 등장하도록! 이동

 

- Collider2D : 기본 도형의 모든 콜라이더 2D 포함

- 몬스터 오브젝트에 Reposition 스크립트 추가, tag - Enemy

- 플레이어가 몬스터를 있도록 Mass(질량) 늘려주기

 

 

6-1. [오브젝트 풀링으로 소환하기]프리팹 만들기

프리팹 생성

- 몬스터 A(해골)

- 몬스터 B(좀비)

 

6-2. [오브젝트 풀링으로 소환하기]오브젝트 만들기

- Instantiate + Destory 함수를 자주 사용하면 메모리 문제 발생

- 변수 : 프리팹들 / 오브젝트 풀들을 저장할 배열 변수

- 리스트 배열 변수 : 크기 = 프리팹 배열 길이

 

6-3. [오브젝트 풀링으로 소환하기]풀링 함수 작성

- foreach : 배열, 리스트 데이터 순차적으로 접근하는 반복문

- 선택한 풀의 비활성화 게임오브젝트 접근

 1. 비활성화 상태 오브젝트 o -> select 변수에 할당

 1) 비활성화 오브젝트 : 활성화 (SetActive)

 2. 비활성화 상태 오브젝트 x -> 생성 로직 실행

 1) 새롭게 생성하고, select 변수에 할당

 2) 생성된 오브젝트, 오브젝트 리스트에 추가

 

6-4. [오브젝트 풀링으로 소환하기]풀링 사용해보기

- 다양한 곳에서 쉽게 접근할 있도록, 게임매니저에 풀매니저 추가

- 프리팹은 장면의 오브젝트에 접근 불가능

-> 생성되면서 변수 초기화해주는 방법 사용

- OnEnable : 스크립트가 활성화 , 호출되는 이벤트 함수

 

6-5. [오브젝트 풀링으로 소환하기]주변에 생성하기

 

 

6+1. [소환 레벨 적용하기]시간에 따른 난이도

FloorToInt : 소수점 아래 버리고 Int형으로 변환

CeilToInt : 소수점 아래 올리고 Int형으로 변환

 

몬스터 소환

- 일정 시간 -> 레벨 (게임 타임 / 10)

- 풀링에서 가져오는 몬스터 종류 -> 레벨

 

6+2. [소환 레벨 적용하기]소환 데이터

- 하나의 스크립트 , 여러 클래스 선언 가능

- 추가 속성 : 스프라이트 타입, 소환시간, 체력, 속도

- 만든 클래스 -> 타입으로 활용하여 배열 변수 선언

- 직렬화 : 개체를 저장 or 전송하기 위해 변환 (인스펙터에서 보이기)

-> System.Serializable 속성 부여

= 직접 작성한 클래스를 직렬화를 통하여 인스펙터에서 초기화 가능

 

6+3. [소환 레벨 적용하기]몬스터 다듬기

- Enemy A, B -> Enemy 하나만 남기고 삭제

- RuntimeAnimatorController 변수 선언

- 인스펙터에서 애니메이션 컨트롤러 변수 초기화 (AcEnemy1, 2 할당)

 

- OnEnable : 생존 여부, 체력 초기화

 

- Init :  초기 속성 적용

- 매개변수 : 소환데이터 -> 매개변수의 속성을 몬스터 속성 변경에 활용

- 애니메이터 변수 선언 초기화

 

6+4. [소환 레벨 적용하기]소환 적용하기

- 매니저에서 데이터 삭제 (Enemy A, Enemy B -> Enemy)

- 소환 시간 조건 변경 : 레벨 -> 소환 데이터

- 오브젝트 풀에서 가져온 오브젝트에서 Enemy 컴포넌트로 접근

- 새롭게 작성한 함수 호출 + 소환데이터 인자값 전달

 

- Mathf.Min : 작은 숫자 반환 (인덱스 에러 해결)

 

 

7-1. [회전하는 근접무기 구현]프리팹 만들기

- 총알 스프라이트 -> 프리팹 생성

- 태그 : Bullet

 

- 스크립트 : 데미지, 관통 변수

- 변수 초기화 함수 : 파라미터 - damage, per

- this : 해당 클래스의 변수로 접근

 

- 박스 콜라이더 2D : Is Trigger 체크 (영역으로만 )

 

7-2. [회전하는 근접무기 구현]충돌 로직 작성

Enemy.cs

- OnTriggerEnter2D : 조건 - 매개변수의 태그 (= 충돌물체 Bullet 맞는지)

- Bullet 컴포넌트로 접근하여 데미지를 가져와 피격 계산

- 남은 체력을 조건으로, 피격 / 사망으로 로직 나누기

- 사망 : 오브젝트 비활성화

 

7-3. [회전하는 근접무기 구현]근접무기 배치

- 근접무기 프리팹(Bullet 0) : 매니저에 등록, Order in Layer - 3 (몬스터(2)보다 높게)

 

Weapon : 무기 생성 관리 담당 (prefabId : 1)

-> 무기 ID, 프리팹 ID, 데미지, 개수, 속도 변수

- Init, Update : 무기 ID 따라 로직 실행

- Init : 생성된 무기 배치하는 함수 호출

 

- Batch : count 수만큼 배치

- parent 속성을 통해 부모 변경

- Bullet 컴포넌트 접근하여 속성 초기화 함수 호출

- 근접 무기 : 관통 숫자 의미 x, 무조건 관통 o

 

7-4. [회전하는 근접무기 구현]근접무기 배치

**회전 이후의 자신의 위쪽 방향으로 이동!

 

회전 : 순서대로 360 나눈 값을 Z축에 적용 - Rotate

이동(위치) : 회전한 상태에서 자신의 위쪽으로 이동 - Translate

- 이동 방향 : Space.World 기준 ! (해주지 않으면, 삽끼리 모양)

 

7-5. [회전하는 근접무기 구현]레벨에 따른 배치

Weapon - 레벨업 기능 함수 (데미지, 개수 증가)

- 속성 변경과 동시에, 배치함수 호출

- Project Settings - Player - Other Settings - Configuration - Active Input Handling : Both

- 배치 : 위치, 회전 초기화부터 하기

- childCount : 자신의 자식 오브젝트 개수 확인

- 기존 오브젝트 먼저 활용하고, 모자란 것은 풀링에서 가져오기

 

 

8-1. [자동 원거리 공격 구현]몬스터 검색 구현

Scanner : 범위, 레이어, 스캔 결과 배열, 가장 가까운 목표

 

- 레이어 : 물리, 시스템 상으로 구분짓기 위한 요소

- CircleCastAll : 원형의 캐스트를 쏘고 모든 결과를 반환

- (1. 캐스팅 시작 위치 2. 원의 반지름 3. 캐스팅 방향 4. 캐스팅 길이 5. 대상 레이어)

 

- GetNearest : 가장 가까운 몬스터를 찾는 함수

- foreach 문으로 캐스팅 결과 오브젝트를 하나씩 접근

-> 반복문을 돌며 가져온 거리가 저장된 거리보다 작으면 교체

- Distance(A, B) : 벡터 A B 거리 계산

 

- FixedUpdate : 지속적으로 가장 가까운 목표 변수 업데이트

 

- 인스펙터 : 범위, 레이어 지정

 

8-2. [자동 원거리 공격 구현]프리팹 만들기

- 스프라이트 교체

 

<Collider>

- Reset : 스프라이트 크기에 맞춰짐

- 콜라이더 : Is Trigger 체크

 

- 새로운 프리팹으로 생성 : Original Prefab 클릭

 

8-3. [자동 원거리 공격 구현]총탄 생성하기

- 총탄 프리팹 : 오브젝트 풀링 매니저에 등록

- 타이머가 speed보다 커지면, 초기화 + 발사 로직 실행

 

- 플레이어 스크립트 : Scanner 타입 변수 선언 + 초기화

- GetComponentInParent : 부모의 컴포넌트 가져오기

* 버그 : 총알 날라가지 x, 그 자리에 생성됨 -> Is Trigger 체크 

 

8-4. [자동 원거리 공격 구현]총탄 발사하기

총탄 : 속도 필요 -> Rigidbody2D 추가

- Gravity Scale : 0

 

<Bullet>

- Rigidbody2D 변수 선언 초기화

- 초기화 함수 : 속도 관련 매개변수 추가

- OnTriggerEnter2D : 관통 =! -1이거나 enemy이면

-> 관통 값이 하나씩 줄어들면서, -1 되면 비활성화 + 미리 물리 속도 초기화

 

<Weapon>

- 크기가 포함된 방향 : 목표 위치 - 나의 위치

- normalized : 현재 벡터의 방향은 유지하고 크기가 1 변환된 속성

- Quaternion.FromToRotation : 지정된 축을 중심으로 목표를 향해 회전

- 원거리 공격에 맞게 초기화 함수 호출 (관통력 넣기)

- Fire()

1) 총알 나아가고자 하는 방향 계산

2) 위치 결정

3) 회전 결정

4) Bullet에게 전달

 

 

9-1. [타격감 있는 몬스터 처치 만들기]피격 리액션

1) 애니메이션

- anim.SetTrigger("Hit")

 

2) 넉백

- 코루틴 : 비동기처럼 실행되는 함수

- IEnumerator : 코루틴만의 반환형 인터페이스

- yield : 코루틴의 반환 키워드

- 1프레임 쉬기 (= 하나의 물리 프레임을 딜레이) : yield return null

- WaitForFixedUpdate 변수 선언 초기화

cf. yield return new WaitForSeconds() : 반복적으로 실행할 , new 계속 사용

-> 최적화 측면 별로 = 변수 만들어서 사용하기

- 플레이어 기준의 반대 방향 : 현재 위치 - 플레이어 위치

- 가하기 : Rigidbody2D - AddForce

- 벡터.normalized : 크기 1 = 방향만 가진 벡터

- 순간적인 : ForceMode2d.Impulse

- StartCoroutine: 코루틴 실행

 

(이동 때문에 넉백 발생 x)

- GetCurrentAnimatorStateInfo : 현재 상태 정보를 가져오는 함수

- IsName : 해당 상태의 이름이 지정된 것과 같은지 확인

 

9-2. [타격감 있는 몬스터 처치 만들기]사망 리액션

죽음

- isLive : false

(- Collider2D : 변수 생성 초기화)

- Collider2D : 비활성화 (enabled = false)

- Rigidbody2D : 비활성화 (simulated = false)

- 죽음 애니메이션 : SetBool - true

- 스프라이트 렌더러의 Sorting Order 감소

 

- 재활용 : OnEnable 함수에서 되돌리기

 

** 비활성화 : 애니메이션 이벤트에서 실행 ** (이거 때문에 애니메이션 실행은 되는데 바로 보이니까 되는 알았음 ㅠㅠㅠㅠㅠㅠ)

- 애니메이션 컴포넌트 : 컨트롤러 교체하면서 다른 애니메이션도 작업

 

9-3. [타격감 있는 몬스터 처치 만들기]처치 데이터 얻기

Header : 인스펙터의 속성들을 이쁘게 구분시켜주는 타이틀

 

<Game Manager>

- 레벨, 킬수, 경험치 변수 선언

- 레벨의 필요경험치 보관 배열 변수 선언

- 경험치 증가 함수 (GetExp)

 

<Enemy>

- 몬스터 사망 : 킬수 증가, 경험치 함수 호출

- 사망 로직이 연달아 실행되는 방지위해 조건 추가 (살아 있을 )

 

 

10-1. [HUD 제작하기]UI 캔버스

World Space : 게임 오브젝트 배치

 

Screen Space : 유저 인터페이스 (GUI, Canvas)

- RectTransform : 스크린 전용 Transform 역할 컴포넌트

- Camera

1) Screen Space - Overlay : 스크린에 그대로 얹음

2) Screen Space - Camera : 스크린을 카메라에 맞춤

3) Wolrd Space : 월드 공간에 배치

 

Canvas * 어느 해상도에서나 크기 유지되도록!

- UI Scale Mode : Scale With Screen Size (cf. Constant : 고정)

- References Resolution : 픽셀 퍼펙트 카메라와 동일하게 적용

 

10-2. [HUD 제작하기]스크립트 준비

- 다루게 데이터(5) : 경험치, 레벨, 킬수, 시간, HP

-> enum(열거형)으로 선언

- 선언한 열거형 : 변수 추가

 

- UI : Text, Slider 변수 선언 초기화

 

- LateUpdate : switch~case문으로 로직 나누기 (데이터 타입 기준)

 

10-3. [HUD 제작하기]경험치 게이지 (Slider)

- Rect Transform : 길이, 높이, 위치, 앵커

 

- 앵커 : UI 오브젝트의 기준점 설정, 변경 오른쪽 속성이 달라짐

1) Shift : 기준점 변경

2) Alt : 위치(크기) 변경

 

<Slider>

- Interactable : 체크 해제

- Transition : None

- Handle Rect : 삭제

- 배경, fill : 전체 확장 늘리기 (shift + alt + 오른쪽 가장 아래)

- Fill Area - Fill : 여백 (Left, Right) - 0

- 슬라이더에 적용할 : 현재 경험치 / 최대 경험치

* 열거형을 변수로 활용하면 사용하기 편한 : 인스펙터에서 선택 가능

 

10-4. [HUD 제작하기]레벨 킬수 텍스트 (Text)

- Format("{0:F0}", 문자열) : 숫자 인자값을 지정된 형태의 문자열로 만들어주는 함수

1) 0, 1, 2... : 순번

2) F0, F1, F2... : 소수점 자리

 

10-5. [HUD 제작하기]타이머 텍스트 (Text)

- Format("{0:D0}", 문자열)

3) D0, D1, D2 ... : 자리 수를 지정

cf. F0, F1 ... : 소수점 자리 지정

 

10-6. [HUD 제작하기]체력 게이지 (Slider)

<Game Manager>

- 체력, 최대 체력 : 변수 선언

- Start : 현재 체력 = 최대 체력

 

<Follow> : 플레이어 따라가는 UI

- RectTransform : 변수 선언 초기화

- 월드 좌표 != 스크린 좌표

1) WorldToScreenPoint : 월드 상의 오브젝트 위치 -> 스크린 좌표로 변환

2) ScreenToWorldPoint

 

11-1. [능력 업그레이드 구현]아이템 데이터 만들기

Item Data : 아이템 데이터 생성을 담당

- Scriptable Object: 다양한 데이터를 저장하는 에셋

- 아이템 각종 속성들 변수로 작성

- Create Asset Menu: 커스텀 메뉴를 생성하는 속성

 

- 생성 : 근접 무기 / 원거리 무기 / 장갑 / 신발 / 체력 회복

 

11-2. [능력 업그레이드 구현]레벨업 버튼 제작

Item

- 아이템데이터, 레벨, 웨폰 : 변수 선언

- 아이콘, 텍스트 레벨

 

- GetComponentsInChildren : 두번째 가져오기 (첫번째 : 자기자신 - 배경 이미지)

 

- LateUpdate : 레벨 텍스트 갱신

 

- OnClick : 버튼 클릭 이벤트와 연결할 함수 (버튼의 OnClick 이벤트에 연결)

-> 아이템 타입을 통해 switch case (여러 개의 case 붙여서 로직 실행 가능)

- 스크립터블 오브젝트에서 작성한 레벨 데이터를 넘기지 않도록!

- 오작동 방지 : Button - Navigation = None

 

11-3. [능력 업그레이드 구현]무기 업그레이드

- 플레이어가 가진 Weapon 오브젝트들 삭제

 

<Item> - OnClick()

- 처음 클릭 : > 코드로 생성 (GameObject newWeapon)

- AddComponent<T> : 게임 오브젝트에 T 컴포넌트 추가

1) 부모 오브젝트 : 플레이어로 지정

2) local Position(지역 위치) : 원점

- 처음 이후의 레벨업 : 데미지, 횟수 계산 (Weapon - 레벨업 함수 활용)

 

<Weapon>

* Init() : 스크립터블 오브젝트 매개변수로 받아 활용

- 각종 무기 속성 변수 : 스크립터블 오브젝트 데이터로 초기화

- prefabId : 풀링 매니저 변수에서 찾아서 초기화 (데이터 = 프리팹 o, 인덱스 x)

 

* Awake : 플레이어 초기화 = 게임 매니저 활용 (이전 : 부모 컴포넌트 가져오기)

 

11-4. [능력 업그레이드 구현]능력 업그레이드 (신발, 장갑, 아이템)

<Gear> : 장비 담당

- 장비 타입, 수치 : 변수

 

* ApplyGear : 타입(장갑/신발) 따라 적용시켜줌

- ApplyGear() 호출 타이밍

1) weapon 새로 생성될

2) weapon 업그레이드 됐을

3) gear 자체가 새로 생성될

4) gear 레벨업 됐을

 

* RateUp : 연사 (장갑)

- 플레이어로 올라가서 모든 Weapon 가져오기

- foreach문으로 하나씩 순회하면서 타입에 따라 속도 올리기

 

* SpeedUp : 이속 (신발)

 

<Item>

- 최초 레벨업 : 게임 오브젝트 생성

- 이후 : 능력 향상

 

<Weapon>

- BroadcastMessage : 특정 함수 호출을 모든 자식에게 방송

-> DontRequireReceiver : 리시버가 없어도 오류 x

 

 

11+1. [플레이어 무기 장착 표현하기]양손 배치

- 왼손 : Sprite Renderer - Order in Layer - 플레이어 보다 높게 (6)

- 오른손 : 플레이어 보다 낮게 (4)

 

11+2. [플레이어 무기 장착 표현하기]반전 컨트롤 구현

<Hand>

- 플레이어의 스프라이트렌더러 : 변수 선언 초기화 (GetComponentsInParent)

 

- 오른손 이동 : Vector3 -> local Position

- 왼손 회전 : Quaternion  -> local Rotation

 

- 왼손, 오른손의 SortingOrder 바꿔주기

 

11+3. [플레이어 무기 장착 표현하기]데이터 추가

<Item Data>

- 스프라이트 담을 속성 추가

 

11+4. [플레이어 무기 장착 표현하기]데이터 연동

<Player>

- 스크립트(hand) 담을 배열변수 선언 초기화

* GetComponent~<Hand>(true) : 인자 true -> 비활성화 오브젝트도 o

 

<Weapon>

- enum : 정수 형태로도 사용 가능 (int) 형변환 필수!

- 스크립터블 오브젝트 데이터 -> 스프라이트 적용

- 오브젝트 활성화 (SetActive)

 

12-1. [레벨업 시스템]UI 완성하기

Layout Group - Control Child Size : 자식 오브젝트를 자신의 크기에 맞게 자동 변경

 

12-2. [레벨업 시스템]아이템 텍스트

<Item Data>

- [TextArea] : 인스펙터에 텍스트 여러 넣을 있음

 (데이터가 들어가는 자리 : {index})

 

<Item>

- 레벨 텍스트 로직 : OnEnable 이동

- switch case : 아이템 타입에 따라 로직 분리 (설명 형태)

- 데미지 % 상승 : 100 곱하기

 

12-3. [레벨업 시스템] 컨트롤

<LevelUP> : 레벨업 관리

- RectTransform 변수 선언 초기화

- Show : 레벨업할

- Hide : 기능 업그레이드 버튼 눌렀을

-> 모든 아이템 버튼 : OnClick - 숨기는 함수 연결

 

<GameManager>

- 레벨업 변수 선언 초기화

- 레벨업 로직 : 보여주는 함수 호출

 

12-4. [레벨업 시스템]기본무기 지급

<Level up>

- 아이템 배열 변수 선언 초기화

- Select : 버튼 대신 눌러주는 함수

-> GameManager - Start에서 실행

 

12-5. [레벨업 시스템]시간 컨트롤

<Game Manager>

- isLive bool 변수 추가

- 시간 정지, 작동 함수 작성

- Time.timeScale : 유니티의 시간 속도(배율) -> 0 = 멈춤

cf. 빨리 감기 기능 : timeScale - 7, 10 ...

-> 스크립트의 Update 계열 로직 : 조건 추가 (GameManager, Player, Enemy, Spawner, Weapon)

 

<LevelUp>

- 레벨업 창이 나타날 : 시간 멈추기

- 레벨업 사라질 : 시간 재생

 

12-6. [레벨업 시스템]랜덤 아이템

<Level Up>

- 랜덤 활성화 함수

1) 모든 아이템 오브젝트 비활성화 (foreach)

2) 중에서 랜덤 3 아이템 활성화

3) 만렙 아이템의 경우 소비 아이템으로 대체

 

 

13-1. [게임 시작과 종료]게임 시작

- Shadow : UI 그래픽을 기준으로 그림자를 생성하는 컴포넌트

- Outline : UI 그래픽을 기준으로 외각선을 그리는 컴포넌트

 

- Start Button - Navigation - None

* 게임 오브젝트 - SetActive : OnClick 이벤트에 바로 사용 가능 !

-> 게임 매니저 - Start : GameStart 변경, 버튼에 연결

 

13-2. [게임 시작과 종료]플레이어 피격

<Player>

* OnCollisionEnter2D : 충돌

- Time.deltaTime -> 적절한 피격 대미지 계산

- childCount : 자식 오브젝트 개수

- GetChild : 주어진 인덱스의 자식 오브젝트 반환

 

13-3. [게임 시작과 종료]게임 시작과 종료

<Game Manager>

* 게임 재시작

- LoadScene : 이름 or 인덱스로 씬을 새롭게 부르는 함수

 

* 게임 오버

- 딜레이를 위해 : 코루틴 작성

- 게임결과 UI 오브젝트 : 게임 오버 코루틴에서 활성화

- 플레이어 사망에서 호출

 

13-4. [게임 시작과 종료]게임 승리

EnemyCleaner : 게임 오브젝트

- BoxCollider2D - Is Trigger 체크, 사이즈 크게

- Tag : Bullet

- 스크립트 : Bullet, 데미지 크게

 

<Result> : 게임 결과 보여줌

* Victory

- 이미지 활성화

- 코루틴 : 죽음 애니메이션 딜레이()

- 게임 시간이 최대 시간 넘기는 호출

 

* GameOver

- 이미지 활성화

- 코루틴 : 죽음 애니메이션 딜레이(플레이어)

- 클리너 활성화

 

<Game Manager>

- 기존 uiResult 변수 타입 변경 : GameObject -> Result

- Start : 시간 재개 함수 호출 (재시작 = TimeScale 변화 x)

- 경험치 얻은 함수 : isLive 필터 추가

 

14-1. [플레이 캐릭터 선택]캐릭터 선택 UI

Grid Layout Group : 자식 오브젝트를 그리드 형태로 정렬하는 컴포넌트

 

14-2. [플레이 캐릭터 선택]선택 적용하기

<Game Manager>

- 캐릭터 ID 저장 변수 선언

 

* GameStart

- int 캐릭터 ID 매개변수 추가

- 기존 무기 지급 함수 : 인자 = 캐릭터 ID

 

- 플레이어 오브젝트 : 미리 비활성화

- 캐릭터 선택 버튼 게임 시작 함수 : 재연결

 

<Player>

- 여러 애니메이터 컨트롤러 저장할 배열 변수 선언

- OnEnable : 애니메이터 변경 로직 추가

 

14-3. [플레이 캐릭터 선택]캐릭터 특성 로직

<Character> : 캐릭터 특성 관리

- 속성 : Speed, WeaponSpeed, WeaponRate, Damage, Count

-> 기존 스크립트 : 속성 사용하는 부분 교체

- 삼항연산자 활용 : 캐릭터에 따라 특성치 적용

 

 

14+1. [캐릭터 해금 시스템]추가 캐릭터 버튼

- 버튼 : OnClick 이벤트 / GameStart 매개변수

-> 캐릭터에 맞게 변경

 

14+2. [캐릭터 해금 시스템]잠금과 해금

<Achieve Manager> : 업적, 해금 관리

* Awake

- 업적 데이터 저장 배열 : 선언 초기화

- Enum.GetValues : 주어진 열거형의 데이터 모두 가져오는 함수

- HasKey : 데이터 유무 체크 Init 실행

 

* Init

- SetInt : key 연결된 int 데이터 저장

- 업적 데이터와 동일한 이름의 key 저장

- foreach : 순차적으로 데이터 저장

 

* UnlockCharacter

- 잠금 버튼 배열 순회 -> 인덱스에 해당하는 업적 이름 가져오기

- GetInt : 저장된 업적 상태 가져와서, 버튼 활성화에 적용

 

- 데이터 지우기 : Edit > Clear All PlayerPrefs

 

14+3. [캐릭터 해금 시스템]업적 달성 로직

<Achieve Manager>

* CheckAchieve : 업적 달성 함수

 

14+4. [캐릭터 해금 시스템]해금 알려주기

<Achieve Manager>

- 알림 오브젝트 저장 변수 선언 초기화

- 코루틴 : 알림 창을 활성화했다가 일정 시간 이후 비활성화

- WaitForSecondsRealtime 변수 초기화(시간 멈출 영향 x) : 불려질 때마다 새로 생성 x

 

 

15-1. [편리한 오디오 시스템 구축]유니티의 오디오

* AudioClip : 오디오 사운드 파일 에셋 타입

* AudioSource : 에셋인 AudioClip 재생시켜주는 컴포넌트

- Play On Awake : 활성화 -> 최초 1 자동 재생

- Camera / AudioListener :  장면에서 재생 중인 오디오를 듣는 컴포넌트

 

15-2. [편리한 오디오 시스템 구축]오디오 매니저

<AudioManager>

- instance 변수 선언 : 정적 메모리에 담기 위해

- 배경음 : 클립, 볼륨, 오디오소스 변수 선언

- 효과음 : 클립, 볼륨, 오디오소스, 채널, 채널 인덱스 변수 선언

 

* Init

- 배경음 플레이어 초기화

1) 배경음 담당 자식 오브젝트 생성

2) AddComponent 오디오소스 생성, 변수에 저장

 

- 효과음 플레이어 초기화

1) 효과음 담당 자식 오브젝트 생성

2) 채널 값을 사용해 오디오 소스 배열 초기화

3) 반복문으로 모든 효과음 오디오 소스 생성하면서 저장

 

- 인스펙터 : 볼륨, 채널 개수 설정

 

15-3. [편리한 오디오 시스템 구축]효과음 시스템

- 모든 효과음 파일 선택, 효과음 배열 변수(Sfx Clips) 드래그 드랍

 

<Audio Manager>

- 효과음과 1:1 대응하는 열거형 데이터 선언 (숫자 지정 가능)

* enum : 문자열 대신 사용 -> 오타 위험 x

 

* PlaySfx : 효과음 재생 함수

0) 채널 개수만큼 순회

1) 효과음 2 이상 : 랜덤 인덱스 더하기

2) 오디오소스의 클립 변경

3) Play 함수 호출

4) 효과음 재생 , 반복문 종료 (break)

- continue : 반복문 도중 다음 루프로 건너뛰는 키워드

 

- 효과음 재생 부분마다, 재생함수 호출

-> Enemy : 피격 (Hit), 죽음 (Dead)

-> GameManager : 시작(Select), 패배(Lose), 승리(Win),

-> LevelUp : 레벨업(LevelUp), 창사라짐(Select)

-> Weapon : 원거리공격 (Range)

 

15-4. [편리한 오디오 시스템 구축]배경음 시스템

<Audio Manager>

* PlayBgm : 배경음 재생 함수

 

* EffectBgm : 필터를 켜고 끄는 함수

- Audio HighPass Filter : 주파수가 높은 음역대만 통과 (카메라 - Listener 존재)

-> Audio Source - Listener Effect 계열 (true : 영향받지 않음 <- 효과음 초기화하는 부분)

 

<Game Manager>

- 게임 시작, 종료(승리/패배) : PlayBgam 호출

 

<Level Up>

- 레벨업 UI 나타날 : 필터 켜기 (EffectBgm - true)

- 레벨업 UI 사라질 : 필터 끄기 (EffectBgm - false)

 

16-2. [로직 보완하기]무한맵 재배치 보완

<Reposition>

- 재배치 로직 : 플레이어 입력 제외 (플레이어의 인풋 벡터)

-> 키를 어떻게 입력하느냐에 따라 결과가 너무 달라지고, 예외 상황 발생

 

- 오브젝트의 위치 차이 활용한 로직으로 변경

1) 방향 구하기

2) 거리 구하기

 

16-3. [로직 보완하기]몬스터 재배치 보완

- 오브젝트(플레이어 - 몬스터) 거리 그대로 활용

- 랜덤 벡터 더하기 : 퍼져있는 몬스터 재배치

 

16-4. [로직 보완하기]투사체 멈춤 보완

- 근거리 무기, 관통력 : -100

- 관통 이후의 로직 : 느슨하게 변경 (per == -1 -> per < 0)

 

16-5. [로직 보완하기]투사체 삭제 추가

- OnTriggerExit2D : 플레이어 Area 밖으로 벗어나면 총알 비활성화

 

16-6. [로직 보완하기]레벨 디자인

<Spawner>

- 소환 레벨 구간 결정 변수 : 선언

- 자동으로 구간 시간 계산 : 최대 시간 / 몬스터 데이터 크기

 

- 필요 경험치 상향 조정

- 최대 게임 시간 재설정

 

 

17-2. [모바일 빌드하기]조이스틱 추가

- Input System / Sample : On-Screen Controls 임포트

- 테두리 이미지 오브젝트 생성

-> 자식 오브젝트로 추가 : stick 프리팹 (편집 : 우클릭 - Prefab / Unpack Completely)

- 조이스틱 오브젝트 : 앵커 아래로 지정, 기본 사이즈 0

- Player - Move 입력 하나 : Stick - On-Screen Path / Control Path 연결되어 있는지 확인

- Player Input - Default Scheme : Gamepad

 

<Game Manager>

- 조이스틱 오브젝트 : 변수 추가 초기화

- 조이스틱 오브젝트 크기 : Stop - 0 / Resume - 1

 

17-3. [모바일 빌드하기]종료 버튼 만들기

- 종료 버튼 - 앵커 : 아래 배치되도록 -> GameStart 크기 확장 (앵커 : 전체크기)

 

<Game Manager>

* 게임 종료 함수 : 종료 버튼 - OnClick 연결

- Application.Quit : 빌드 버전에서만 작동 (에디터 종료 기능 x)

 

17-4. [모바일 빌드하기]렌더러와 프레임 지정

* Edit > Project Settings

- Quality : Medium 남기고 삭제

- Rendering : 렌더파이프라인 에셋 넣기 (URP)

- Vsync Count : Dont Sync (모바일 : 적용 x)

- 게임 - Stat : 프레임률 확인

 

<Game Manager>

- 직접 프레임 지정 : targetFrameRate 속성 설정

 

17-5. [모바일 빌드하기]포스트 프로세싱

- - 오브젝트 추가 : Volume > Global Volume

-> New : 볼륨 프로파일 에셋 추가

-> Add Override(후처리 추가) : Bloom, Film Grain, Vignette

- Bloom( 번짐 효과) : Threshold(한계점, 역치 - 작을수록 흰색), Intensity(세기), Scatter(범위)

- Film Grain (필름 노이즈 효과) : Type, Intensity, Response(패턴 달라짐)

- Vignette (모서리 음영 처리 효과) : Color, Center, Intensity, Smoothness

 

- Main Camera - Rendering : Post Processing 체크

 

17-6. [모바일 빌드하기]모바일 시뮬레이터

- Simulator : 기기 회전, 안전 구역 미리 확인 가능

-> UI 배치 확인, 알맞게 수정

 

17-7. [모바일 빌드하기]모바일 빌드

File > Build Settings

- 안드로이드 플랫폼 선택 , Switch Platform

 

Player Setting

- 어플리케이션 기본 정보 입력 : Company Name, Product Name, Version, Default Icon

- Resolution and Presentation : Hide Navigation Bar - 체크 해제, Allowed Orientations for Auto Rotation - Landscape Right/Left 해제

- 개인 라이선스 : 게임 시작 - splash 화면 등장

- Other Settings - Minimum API Level, Target API Level : 그대로 (안드로이드 레벨)

- 64비트 : Configuration - Script Backend - IL2CPP, Target Architectures - ARMv7, ARM64 체크