✨ 이 귀여운 프로젝트를 만들기 위해 공부했던 것들을 정리해보았다!
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("플레이어와 충돌 발생!");
}
}
🔹충돌 감지가 작동하려면?
- 이 오브젝트나 플레이어 중 하나는 Rigidbody2D가 있어야 함(나는 플레이어에 Rigidbody2D붙여놨음)
- 이 오브젝트에 Collider2D가 있어야 함
- Is Trigger 체크 여부에 따라 OnTrigger or OnCollision 선택
- 태그를 정확하게 비교 (예: "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
✅ 정렬 구성 방법
- ButtonGroup에 Horizontal Layout Group(가로배치) 추가
- Spacing: 20
- Child Alignment: Middle Center
- Child Force Expand > Width, Height 체크 해제
- 전체 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꾸미기)
- 압축 풀고 PNG 파일 Unity로 드래그
- Inspector 설정
- Texture Type: Sprite (2D and UI)
- Filter Mode: Bilinear / Point
- Compression: None
- 버튼 이미지로 적용
- Button > Image 컴포넌트에서 Source Image 변경
- 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);
'GameDevelop > Unity기초쌓기' 카테고리의 다른 글
Unity Scene 창 초기화 & Game 뷰와 일치시키기 (0) | 2025.05.21 |
---|---|
Unity Font에서 Font Asset만들기 (0) | 2025.05.19 |
[Unity-2025.05.02] Lerp (0) | 2025.05.02 |
Unity 싱글톤(Singleton) 패턴 (0) | 2025.05.01 |
[FlappyPlane] Unity 좌표계 이해하기 - 로컬좌표 vs 월드좌표 (0) | 2025.05.01 |