https://youtube.com/playlist?list=PLO-mt5Iu5TeZF8xMHqtT_DhAPKmjF6i3x&si=CdE5wqKi4lrlC0UR
유니티 기초 뱀서라이크🧟언데드서바이버
요즘 인기많은 장르인 뱀서라이크를 직접 유니티로 개발해보아요!
www.youtube.com
모바일 빌드까지 완료해봤당
빌드과정에서... 내가 최근 apk로 빌드를 못했던 게 내 탓이 아니라 유니티 에디터 잘못인 걸 알게 되었고
고치느라 며칠을 고생했다 🥲
처음 사용해본 것 : 애니메이션 오버라이드 컨트롤러, Input System
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 체크
'강의 > Unity' 카테고리의 다른 글
[오늘코딩]국가권력급 유니티 꿀팁 (0) | 2024.08.30 |
---|---|
유니티 비동기 프로그래밍 - 1. Coroutine 이해 (0) | 2024.07.28 |
유니티 비동기 프로그래밍 - 0. 비동기 프로그래밍 (0) | 2024.07.27 |