GameDevelop/Unity기초쌓기

[Unity-2025.05.06] topdown_project TIL(Today I Learned)

도도돋치 2025. 5. 6. 19:51
Contents 접기
728x90

✨ 이 귀여운 프로젝트를 만들기 위해 공부했던 것들을 정리해보았다!


1. 카메라 이동 관련 개념 정리

플레이어를 카메라가 따라갈 수 있도록 설정해야 한다.

 

🔹 transform.position 이란?

 

쉽게 설명하면, " 스크립트가 붙어 있는 애의 위치를 말하는 것!"

  • 모든 Unity 오브젝트는 Transform 컴포넌트를 기본적으로 가지고 있음
  • transform.position 해당 오브젝트의 현재 위치를 의미
  • 별도로 선언하지 않아도 MonoBehaviour를 상속하면 자동으로 접근 가능
  • Transform 오브젝트의 위치(position), 회전(rotation), 크기(scale) 담당
void Start() {
    Debug.Log(transform.position); // 이 스크립트가 붙은 오브젝트의 위치 출력
}

스크립트를 카메라 오브젝트에 붙이면, transform.position 카메라의 현재 위치 출력하게 된다.

📝  관련 예시 

코드 의미
transform.position  오브젝트의 위치
transform.rotation  오브젝트의 회전 
transform.localScale  오브젝트의 크기 (자기 기준)
transform.Translate(...)  오브젝트를 움직이기
transform.LookAt(...) 어떤 방향을 바라보게 하기

그리고 플레이어를 따라가게 하기 위해서 target의 위치도 가져올 수 있다.(유니티에디터에서 player를 넣어주면 된다.)

public Transform target;

 

 

 

2. CameraFollow 스크립트는 어디에 붙여야 할까?

아까 카메라의 이동을 담당하는 CameraFollow스크립트를 만들어 주었다. 그렇다면 이 스크립트는 어디에 붙여야할까?

  • 반드시 Main Camera에 붙여야 함
  • target은 플레이어의 Transform
  • 카메라가 플레이어를 따라다니는 구조
// 사용 방법 요약
1. Main Camera에 CameraFollow 스크립트 추가
2. Target에 플레이어 오브젝트 드래그
3. minBounds, maxBounds로 이동 범위 제한 가능
붙이는 대상 이유
 Main Camera 카메라가 플레이어를 따라가게 만들기 위해서
 
 

3. 왜 Clamp(minBounds, maxBounds)가 필요할까?

타일맵이나 배경 이미지가 100x100인데, 카메라가 120, 120 같은 위치까지 가버리면 "배경 없는 빈 화면"이 보이게 된다.

 , 플레이어는 중앙에 있지만 카메라가 너무 멀리 가면 외곽까지 노출된다.

 

🔹아래 사진의 Main Camera가 플레이어가 보는 화면인데, 최대 최소값을 설정 안해줬을때 타일 맵 바깥의 빈 배경이 보인다.

 

🔹 설정을 해주면 아래처럼 플레이어가 맵의 끝쪽으로 가도 바깥 배경이 안보이는 것을 확인 할 수 있다

📖 요약

  • 카메라가 맵 밖으로 나가서 빈 공간이 보이는 걸 방지하기 위함
  • 연출/게임성 유지, 플레이어 몰입 깨는 것 방지
  • Clamp로 경계 제한하면 게임 플레이가 훨씬 안정적임

 

4. Bounds와 Vector3/Vector2 차이

🔹 카메라 최대, 최소 설정을 위해 타일맵의 좌표를 가져오도록 Bounds를 사용하였다. Bounds는 무엇일까?

Bounds localBounds = tilemap.localBounds;
minBounds = new Vector2(localBounds.min.x+9, localBounds.min.y+5);
maxBounds = new Vector2(localBounds.max.x-9, localBounds.max.y-5);

 

Bounds"3D 공간 안의 박스형 영역(사각형 또는 직육면체)" 의미한다.
, 타일맵이나 콜라이더, 스프라이트 등이 차지하는 실제 공간 나타낼 Unity Bounds 객체를 사용한다.

 

 

🔹Bounds에는 다음 정보가 들어있다

속성 설명
bounds.min 박스의 왼쪽 아래 뒷면 모서리 좌표 (Vector3)
bounds.max 박스의 오른쪽 앞면 모서리 좌표 (Vector3)
bounds.center 중심점 (Vector3)
bounds.size 가로 x 세로 x 깊이 크기 (Vector3)

→ min max 박스의 좌표 경계값이고, 이걸 가지고 우리는 카메라가 벗어나지 않게 제한 거는 것이다.

 

🔹 minBounds, maxBounds Vector2인데 transform.position Vector3일까?

항목 타입 이유(Unity 모든 오브젝트의 위치는 3D 기준 (x, y, z))
Bounds Vector3 기반 타일맵, 콜라이더 등의 3D 공간 경계 값, 실제 공간의 3D 경계 박스이기 때문
transform.position Vector3 Unity 기본적으로 3D 좌표계 사용
minBounds,maxBounds Vector2 2D 게임에서는 X, Y만 제한하면 되므로 Vector2 사용
카메라는 2D로만 움직이면 되니까 Z 생략

 

 카메라는 3D 공간에서 움직이지만, 2D 게임에선 Z축(깊이)이 고정되어 있기 때문이다.

 

🔽 transform.position은 언제나 Vector3

  • Unity의 모든 GameObject는 3D 좌표계(x, y, z)에서 존재한다.
  • 비록 2D 게임을 만들고 있어도 Camera, Player, Enemy 전부 z축 값이 존재한다.
  • 그래서 transform.position은 무조건 Vector3로 되어 있다.

🔽 minBounds, maxBounds는 2D 제한만 걸면 되니까 Vector2

  • 우리는 카메라가 X축, Y축으로만 움직이도록 제한하고 싶다.
  • Z축은 카메라의 깊이(보통 -10)로 항상 고정이니까 신경 안 써도 된다.
  • 그래서 minBounds와 maxBounds는 "2차원 제한이기 때문에 Vector2"로 간단히 처리하는 것이다.

💡 예를 들어

Vector3 desiredPosition = target.position + offset;
desiredPosition.x = Mathf.Clamp(desiredPosition.x, minBounds.x, maxBounds.x);
desiredPosition.y = Mathf.Clamp(desiredPosition.y, minBounds.y, maxBounds.y);
desiredPosition.z = -10f; // Z축은 고정
  • 여기서 desiredPosition은 카메라 위치니까 Vector3
  • 하지만 Clamp 기준인 min/maxBounds는 X와 Y만 제한하면 되므로 Vector2

 

 

5.  왜 Player 밑에 MainSprite를 따로 만들까?

이유 설명
기능과 외형 분리 Player는 Rigidbody2D, MainSprite는 SpriteRenderer, Animator 담당
애니메이션 전용 구조 외형만 교체하거나 흔들림 연출이 필요할 때 좋음
확장성 확보 무기, 그림자, HP바 등 자식 오브젝트를 붙이기 쉬움

 

이유 1. 충돌 처리와 시각 효과를 분리하기 위해

Player 오브젝트에는 Rigidbody2D, Collider2D 같은 물리 처리 컴포넌트를 붙이고, MainSprite에는 SpriteRenderer만 붙임

 

🔹 이렇게 하면:

  • 충돌이나 이동은 Player가 담당
  • 외형(이미지/애니메이션)은 MainSprite가 담당

→ 수정하거나 애니메이션을 교체할 때 기능에 영향 없이 이미지만 바꾸기 쉬워진다.

 

이유 2. Sprite에 애니메이션이나 이펙트를 따로 주기 위해

MainSprite에만 Animator를 붙이고, 필요하면 다른 이펙트(Shadow, Aura, Weapon 등)를 자식으로 추가할 수 있다.

  • 구조적으로 확장하기 좋다.
  • 이펙트가 흔들리거나 회전해도 물리 위치는 안정적으로 유지할 수 있다.

 

이유 3. 다른 자식 오브젝트를 쉽게 붙이기 위해

  • MainSprite(캐릭터 외형)
  • WeaponSprite(검, 총 등 무기)
  • HealthBarUI, NameTag(위에 뜨는 UI)

이렇게 시각적인 것들을 전부 Player 밑에 자식으로 배치 있다.

 

🔹 예시 구조:

Player (Rigidbody2D, 이동 스크립트)
├── MainSprite (SpriteRenderer, Animator)
├── WeaponSprite
├── Shadow

 

 

6. Collider를 충돌 감지용으로 쓰기

위 사진의 레버를 왼쪽에서 밀면 미니게임이 연결되는 구조를 구현하기 위함이다. 

 

충돌 감지용으로 Collider2D를 쓰려는 거라면, Unity에서는 크게 두 가지 방식이 있다.

 

🔹충돌 감지용 Collider2D 설정

용도 Collider 종류 필수 조건
실제 충돌 감지 (물리 반응 포함) BoxCollider2D, CircleCollider2D Rigidbody2D
충돌만 감지하고 통과 (Trigger) Collider2D + Is Trigger 체크 Rigidbody2D 

 

🔹코드로 충돌 감지하는 방법 (OnTriggerEnter2D / OnCollisionEnter2D)

✔️ 무조건 메서드 이름은 "정확히 OnTriggerEnter2D"여야 한다. 이게 2D Collider 감지를 위한 Unity 예약 함수이다.

 

👉 Is Trigger = 일 때:

void OnTriggerEnter2D(Collider2D other)
{
    if (other.CompareTag("Player"))
    {
        Debug.Log("플레이어가 포탈에 닿았어요!");
        // 씬 이동 등 로직 실행
    }
}

 

👉 Is Trigger = (일반 충돌)일 때:

void OnCollisionEnter2D(Collision2D collision)
{
    if (collision.gameObject.CompareTag("Player"))
    {
        Debug.Log("플레이어와 충돌 발생!");
    }
}

 

🔹충돌 감지가 작동하려면?

  1. 이 오브젝트나 플레이어 중 하나는 Rigidbody2D가 있어야 함(나는 플레이어에 Rigidbody2D붙여놨음)
  2. 이 오브젝트에 Collider2D가 있어야 함
  3. Is Trigger 체크 여부에 따라 OnTrigger or OnCollision 선택
  4. 태그를 정확하게 비교 (예: "Player")

 

💡 꿀팁: GetComponent로 Collider2D를 직접 가져와서 쓸 수도 있다.

BoxCollider2D myCol = GetComponent<BoxCollider2D>();
myCol.enabled = false;  // 충돌 끄기

 

 

요약

목표 조건 코드
충돌 감지 (통과 가능) Is Trigger = true OnTriggerEnter2D
충돌 감지 (부딪침 포함) Is Trigger = false OnCollisionEnter2D
코드에서 Collider 제어 GetComponent<Collider2D>() enabled, offset, size 변경 가능

 

 

7. Text종류별 차이

Text를 쓰려고 보니까 굉장히 많은 Text종류들이 있었다. 무슨 차이일까?

 


🔹Unity에서 보이는 Text 관련 UI 컴포넌트 비교

 

항목 설명 UI? 지금 추천?
TextMeshPro - Input Field 입력창 (사용자가 입력 가능)
TextMeshPro - Text TMP 텍스트 (3D/Canvas 공통)
TextMeshPro - Text (UI) TMP 텍스트 (UI Canvas 전용)
Text 옛날 방식 UI 텍스트 (이제 거의 )
Text Mesh 3D 오브젝트에 붙는 기본 텍스트 (Mesh 기반) (낡은 방식)
Dropdown - TextMeshPro TMP 기반 드롭다운 메뉴
Text Container (TMPro) TMP 내부용, 직접 추가 X

🔹요즘 Unity에서 텍스트 쓸 땐?

 

무조건 TextMeshPro 계열로 쓰는 게 표준

이유:

  • 훨씬 더 선명한 글꼴 렌더링
  • 텍스트 꾸미기 (굵게/기울임/그라디언트/이모지 등) 지원
  • 폰트 크기 자동 맞춤, 정렬, 마스크 등 유연함
  • UI/비UI 겸용 가능 (Text, Text (UI)로 구분만 하면 됨)

🔍 각 항목 설명 더 자세히 보기

 

1. TextMeshPro - Text

  • TMP 텍스트의 기본형
  • 3D 오브젝트에도 사용 가능 (UI 아니어도 OK)
  • Ex: 월드 공간에 떠 있는 숫자, 이름표 등

2. TextMeshPro - Text (UI)

  • Canvas 위에서 UI로 쓸 때 전용
  • Panel, 버튼 등에 넣을 때 이걸 써야 함
  • 대부분 UI에선 이걸 씀!

3. Text

  • UnityEngine.UI.Text
  • Unity 2019 이전 시대에 많이 쓰던 기본 UI 텍스트
  • 현재는 TextMeshPro에 밀려 거의 안 씀

4. Text Mesh

  • 진짜 3D 오브젝트에 사용하는 Mesh 기반의 옛날 텍스트
  • 거의 사용 안 함 (대체로 TMP 사용)
목적 추천 컴포넌트
UI 텍스트 보이기 TextMeshPro - Text (UI)
입력 필드 (닉네임, 채팅 ) TextMeshPro - Input Field
3D 월드에 있는 텍스트 TextMeshPro - Text (또는 World Space UI)

 

💡 참고

  • TMP를 처음 쓰면 Unity가 "TMP 필수 리소스를 Import하겠냐"고 묻는다 → 무조건 YES!
  • TMP 패키지지만 Unity 기본 설치에 포함돼 있으니 자유롭게 사용해도 안전하다.

 

8. UI 레이아웃 꿀팁: 텍스트 + 버튼 팝업 구성하기

[ 목표 ]
"성공", "게임 오버", "확인/취소" 같은 UI 팝업을 자동 정렬로 만들기

Canvas
└── Panel (Vertical Layout Group)
    ├── TitleText (TextMeshPro)
    └── ButtonGroup (Horizontal Layout Group)
        ├── ConfirmButton
        └── CancelButton

✅ 정렬 구성 방법

  1. ButtonGroup에 Horizontal Layout Group(가로배치) 추가
    • Spacing: 20
    • Child Alignment: Middle Center
    • Child Force Expand > Width, Height 체크 해제
  2. 전체 Panel에 Vertical Layout Group도 가능
    • 버튼 뿐 아니라 제목+버튼 전체를 정렬하고 싶을 때
    • Panel 오브젝트 선택
    • Add Component > Vertical Layout Group 추가
    • 버튼/텍스트가 자동으로 세로로 정렬됨
    • Content Size Fitter를 추가하면 크기도 자동 조절됨
    • Content Size Filtter Vertical Fit: Preferred Size

3. 버튼에는 TextMeshPro - Text 사용 (UI 전용)

 

그룹 종류 정렬 방향 사용 위치
Horizontal Layout Group 우로 나열 버튼 2 이상
Vertical Layout Group 아래로 나열 제목 + 내용 + 버튼
Content Size Fitter 내용에 맞게 크기 조절 텍스트, 버튼 그룹

 

🔹 최종 구조 예시

Panel (Vertical Layout Group)
├── TitleText (TextMeshPro)
└── ButtonGroup (Horizontal Layout Group)
    ├── ConfirmButton
    └── CancelButton

 

이렇게 하면 반응형 + 정렬 + 유지보수가 쉬운 UI를 만들 수 있다!!


🧩 Kenney UI Pack 사용하는 법(버튼 UI꾸미기)

  1. 압축 풀고 PNG 파일 Unity로 드래그
  2. Inspector 설정
    • Texture Type: Sprite (2D and UI)
    • Filter Mode: Bilinear / Point
    • Compression: None
  3. 버튼 이미지로 적용
    • Button > Image 컴포넌트에서 Source Image 변경
  4. Sliced로 설정하면 크기 확대에도 모서리 둥글게 유지
    • Sprite Editor > Border 설정

 

9. Scene 추가하기

다른 곳에서 만든 게임 Scene을 추가해보자!

유니티에디터에서 File> Build Settings로 들어간다. 

그리고 Add Open Scenes를 누르면 추가 할 수 있다.

 

10. 3D게임에서 배경색이 안바뀐다

이렇게 Camera를 고정색으로 설정해주어야한다.

 

또한 A가 0으로 가있지는 않은지 확인해보자.

11. 카메라 최대 최소를 설정해줬는데 아직 배경이 보인다

카메라는 Size를 가지고 있기 때문에 카메라가 가지고 있는 Size만큼도 계산을 해주어야한다.

 

아래 코드에 보면 min과 max에 카메라 사이즈를 계산해 준 것을 볼 수 있다.

 offset = transform.position - target.position;

Bounds localBounds = tilemap.localBounds;
minBounds = new Vector2(localBounds.min.x+9, localBounds.min.y+5);
maxBounds = new Vector2(localBounds.max.x-9, localBounds.max.y-5);
728x90