GoldMetal 유튜브의 [Undead Survivor]라는 프로젝트를 따라서 진행! --> 2D 플랫폼의 전반적인 이해와 Unity 사용법 숙달!
이전부터 하던 작업이 있었는데, 까먹고 Tistory에 올리지 못했다....오늘부터라도 차근차근 올려야지
ㅡㅡㅡㅡㅡㅡ이전까지 했던 작업ㅡㅡㅡㅡㅡㅡ
[2D 오브젝트 제작] --> Undead Survivor에서 직접 조종할 수 있는 플레이어블 캐릭터 만들기
- Pixel Per Unit : 주 캐릭터의 실제 크기로 설정
- Filter Mode : Point로 설정
- Compression : None으로 설정
- Sprite Mode : Multiple로 변경 후 스프라이트를 열어서 각 모션별로 자르기
- sprite 하나를 Scene에 드래그&드랍 후 이름 변경
- Add Component
- Rigidbody 2D : 오브젝트의 물리적인 상호작용
- (Shape) Collier 2D : 오브젝트의 충돌 면 관리(Shape 모양으로) - Sprite Renderer의 Order in Layer를 높게 설정
(Order in Layer는 오브젝트가 겹쳐질 때, 어떤 오브젝트가 위로 가야하는지를 관리)
[플레이어 이동 구현] --> 플레이어블 캐릭터의 이동 구현
- C# 스크립트 생성(Player)
(생성이 완료될 때 까지 잠깐 기다린다. 생성 중에 스크립트를 열어버리면 오류가 난다!!!)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public Vector2 inputVec; // 벡터 변수 선언
public float speed;
Rigidbody2D rigid; // Rigidbody2D 변수 선언 <이전에 Add Component에서 봤었다>
void Awake() // 시작할 때 한번만 실행
{
rigid = GetComponent<Rigidbody2D>(); // 게임 오브젝트 변수는 Awake 함수에서 초기화
}
void Update() // 매 프레임마다 호출
{
inputVec.x = Input.GetAxisRaw("Horizontal"); // Input Manager의 x축 값 가져오기
inputVec.y = Input.GetAxisRaw("Vertical"); // Input Manager의 y축 값 가져오기
}
void FixedUpdate() // 물리 연산 프레임마다 호출 (물리 효과가 적용된 오브젝트를 조정할 때 사용)
{
Vector2 nextVec = inputVec.normalized * speed *Time.fixedDeltaTime; // 플레이어블 캐릭터가 다음 프레임에 움직여야 하는 방향과 속도를 지정
rigid.MovePosition(rigid.position + nextVec); // 기존의 위치에 움직여야 하는 방향과 속도를 더함
}
}
[2D 셀 애니메이션 제작] --> 캐릭터의 애니메이션 제작
- 방향 바라보게 하기
기존의 코드에 아래 코드 추가
private void LateUpdate()
{
if (inputVec.x != 0) // inputVec.x 값이 0이 아니면 if문 실행
{
spriter.flipX = inputVec.x < 0; // inputVec.x 값이 음수이면(캐릭터가 왼쪽으로 이동하면) x축 대칭 전환 실행
}
}
- sprite에서 죽을 때, 뛸 때, 서있을 때 등등 모션 별로 Player에 다중선택 드래그&드랍하여 애니메이션 만들기
- Animator 화면 들어가기
- Stand 모션을 Default State로 설정
- Stand 모션 <--> Run 모션 Make Transition
- Any State --> Dead 모션 Make Transition
- Parameters에 float : Speed, trigger : Dead 제작
- Stand 모션 --> Run 모션 Transition Conditions에 Speed | Greater | 0.01 추가
- Run 모션 --> Stand 모션 Transition Conditions에 Speed | Less | 0.01 추가
- Any State --> Dead 모션 Transition Conditions에 Dead 설정 - Project\Animations\Dead 모션 Loop Time 체크 해제
- 애니메이션 코드 작성
아래는 완성된 코드
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public Vector2 inputVec;
public float speed; // 상수 변수 선언 (animator parameter에 상수 Speed가 있었으니 코드에도 만드는 것임)
Rigidbody2D rigid;
SpriteRenderer spriter; // Scene에 보이게 하는 SpriteRenderer 변수 선언
Animator anim; // Animator 변수 선언
void Awake()
{
rigid = GetComponent<Rigidbody2D>();
spriter = GetComponent<SpriteRenderer>(); // 게임 오브젝트 변수는 Awake 함수에서 초기화
anim = GetComponent<Animator>(); // 게임 오브젝트 변수는 Awake 함수에서 초기화
}
void Update()
{
inputVec.x = Input.GetAxisRaw("Horizontal");
inputVec.y = Input.GetAxisRaw("Vertical");
}
private void FixedUpdate()
{
Vector2 nextVec = inputVec.normalized * speed *Time.fixedDeltaTime;
rigid.MovePosition(rigid.position + nextVec);
}
private void LateUpdate()
{
anim.SetFloat("Speed", inputVec.magnitude);
// InputVec 상수값의 크기만 받아옴 --> condition에서 설정한 대로 0.01보다 크면 Run 모션 실행, 작으면 Stand 모션 실행
if (inputVec.x != 0)
{
spriter.flipX = inputVec.x < 0;
}
}
}
[무한 맵 이동] --> 기존의 맵을 재사용하여 화면에 끊임없이 맵을 만들기
- 메뉴 바 Window > 2D > Tile Palette로 팔레트 창 열기
- Tile 폴더에서 우클릭 후 2D > Tiles > Rule Tile로 타일 에셋 생성
- Number of Tiling Rules 값을 1로 변경
- Tiling Rules\Output을 Random으로 변경
- Tiling Rules\Size 10으로 변경(Size에 들어가는 타일은 비율대로 화면에 나타난다)
- Tile sprite를 Size 빈 칸에 드래그&드랍
- Hierachy에서 우클릭 후 2D Object > TileMap > Rectangular 선택 --> 이름 정해주기
- Hierachy에서 타일맵 선택
- Tile Palette\Default Brush를 Tile Palette\Line Brush 선택 후 타일맵 그리기(20x20) - Tilemap에 Add Component
- Tilemap Colidar 2D --> Used By Composite 체크
- Composite Collidar 2D(타일마다 나눠진 형태를 하나로 합쳐준다) --> Is Trigger 체크
- 자동으로 생성되는 Rigidbody 2D --> Body Type을 Static 설정 - Tag를 눌러 Add Tag
- Ground
- Area - Tilemap 태그를 Ground로 변경
- Hierachy의 Player 우클릭 후 Create Empty --> 이름 Area로 변경
- Area에 Add Component
- Box Collidar 2D --> Is Trigger 체크 - Area 태그를 Area로 변경
- Codes 폴더에서 C# 스크립트 생성 --> 이름 Reposition로 설정
- Codes 폴더에서 C# 스크립트 생성 --> 이름 GameManager로 설정
(GameManager에 중요한 내용을 넣어 깔끔한 코딩) - Hierachy에서 Create Empty --> GameManager로 이름 변경
- GameManager 스크립트 Hierachy\GameManager에 드래그&드랍 - GameManager 스크립트 작성
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
public static GameManager instance; // 정적 변수는 즉시 클래스에서 부를 수 있어 편리하다
public Player player; // inspector 화면에 나타남 --> hierachy의 Player를 드래그&드랍
private void Awake()
{
instance = this; // 인스턴스 변수를 자기자신 this로 초기화
}
}
- Reposition 스크립트 작성
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Reposition : MonoBehaviour{
private void OnTriggerExit2D(Collider2D collision){
if (!collision.CompareTag("Area")){ // 오브젝트의 Tag가 Area가 아닐 경우, 실행 x
return;
}
Vector3 playerPos = GameManager.instance.player.transform.position;
Vector3 myPos = transform.position;
float diffX = Mathf.Abs(playerPos.x - myPos.x);
float diffY = Mathf.Abs(playerPos.y - myPos.y);
Vector3 playerDir = GameManager.instance.player.inputVec;
float dirX = playerDir.x < 0 ? -1 : 1;
float dirY = playerDir.y < 0 ? -1 : 1;
switch (transform.tag){ // 태그를 비교하는 함수
case "Ground":
if(diffX > diffY){ // 이동거리의 X축이 Y축보다 크면 타일을 X축으로 재활용
transform.Translate(Vector3.right * dirX * 40);
}
else if (diffX < diffY){ // 이동거리의 Y축이 X축보다 크면 타일을 Y축으로 재활용
transform.Translate(Vector3.up * dirY * 40);
}
break;
case "Enemy":
break;
}
}
}
- 타일 맵 오브젝트를 Ctrl + D 로 3번 복사하여 Player를 중심으로 배치(40x40이 되도록)
- Hierachy의 Main Camera에 Add Component
- Pixel Perfect Camera
- Assets Pixels Per Unit을 스프라이트에서 사용하는 수치와 맞추기
- Reference Resolution(카메라 크기 계산을 위한 참고 해상도) 적당히 맞춰주기
(타일맵 크기, Area 크기, 재배치 거리는 카메라 크기와 비슷하게!) - Window > Package Manager > Unity Registry > Cinemachine 설치
- Hirachy에서 우클릭 후 Cinemachine > Virtual Camera 생성
(Virtual Camera는 Main Camera의 카메라 감독이다) - Virtual Camera의 Follow에 Player 오브젝트 드래그&드랍
- Cinemachine Brain의 Update를 FixedUpdate로 변경
- Tilemap Renderer의 Order in Layer 낮추기
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
★Slow and Steady★
'Unity 공부 > Unity_2D' 카테고리의 다른 글
| [Day 5] 회전하는 근접무기 구현 (0) | 2023.07.11 |
|---|---|
| [Day 4] 소환 레벨 적용 (2) | 2023.07.10 |
| [Day 3] 오브젝트 풀링으로 소환 (0) | 2023.07.09 |
| [Day 2] 몬스터 제작 (0) | 2023.07.08 |
| Project_Moon 입사를 꿈꾸며.... (0) | 2023.06.23 |