팀스파르타 내일배움캠프

🧠 2025 Unity 3D 입문 주차 - 5월 21일 TIL

creator2041 2025. 5. 22. 00:43

 

🎮 PlayerCondition 시스템 구현 및 디버깅

🔧 핵심 흐름 정리

  • Condition.cs: 상태 수치 (current, max, passive) 를 관리하는 공통 컴포넌트
  • PlayerCondition.cs: 헝거(Hunger), 체력(Health), 정신력(Sanity) 간 상호작용 로직 작성
  • UICondition.cs: 상태 값을 UI 슬라이더와 연결하여 실시간 반영

🧨 주요 문제 및 해결 과정

  • 현상: 시간이 지나도 Hunger가 감소하지 않고 오히려 증가
  • 원인: passiveValue가 음수값(-20) → Subtract(-x) = Add(x) 효과
  • 해결: Mathf.Abs()로 양수 처리하여 항상 감소 방향 보장
hunger.Subtract(Mathf.Abs(hunger.passiveValue) * Time.deltaTime);
  • 헝거가 0에 도달하면 체력이 감소하도록 연동 (의도한 리스크 감정 설계 구현)
  • 콘솔 로그 디버깅 습관 형성 → 실시간 수치 변화를 추적해 원인 빠르게 파악 가능

🧱 UI 자동 정렬 시스템: Vertical Layout Group 활용 체험

🎯 실습 내용

  • Vertical Layout Group 컴포넌트를 활용해 버튼, 상태창 등의 UI를 자동으로 수직 정렬
  • Content Size Fitter를 함께 적용해 자식 오브젝트 크기에 따라 부모 영역 자동 조절
  • 불필요한 수동 위치 조정 없이 정렬 가능해짐

✨ 느낀 점

  • UI를 코드로 움직이지 않아도 정렬이 자동으로 해결되는 경험은 처음이었음
  • 다양한 해상도, 콘텐츠 길이 변화에도 유연하게 대응됨 → 유지보수 용이
  • Scroll View의 내부 콘텐츠 영역에 필수적 요소임을 체감

“정렬은 코딩이 아니라 컴포넌트 설정으로 끝낼 수 있다.” → UI에 대한 생각 전환


🔒 코드 안정성 확보: 방어 코드와 싱글턴 보호 구조 적용

✅ Null 방지 체크 습관화

if (target != null)
{
    target.DoSomething();
}
  • 오브젝트 참조가 사라졌을 때 발생하는 NullReferenceException 방지 습관 확립

✅ DontDestroyOnLoad 적용 실습

  • 씬이 전환되어도 오브젝트를 유지하기 위한 구조 구현
  • 게임 매니저, BGM 컨트롤러 등은 DontDestroyOnLoad()로 생존 보장

🚨 실습 중 실수로 싱글턴 오브젝트가 중복 생성되는 문제도 겪음 → 조건 검사 필요함


🛠️ 생산성 도구 활용 습관 정착

✅ 불필요한 using 정리 습관화

작업 단축키 (Visual Studio 기준)

using 제거 Ctrl + R, G
코드 자동 정렬 Ctrl + K, D
선택 영역만 정렬 Ctrl + K, F

✅ 코드 탐색 효율화

  • Ctrl + 클릭: 클래스/메서드 정의로 즉시 이동
  • Alt + ← / →: 앞뒤 탐색 히스토리 이동 (실전에서 탐색 피로도 극감함)

Ctrl + 클릭은 오늘 처음 썼지만 앞으로 중독될 예정. "코드의 순간이동" 체감 완료.


⚠️ 메서드 시그니처 충돌 경험 및 조치

🧨 발생 오류

'PlayerCondition' 형식은 동일한 매개 변수 형식을 가진 'Heal' 멤버를 미리 정의합니다.
  • 원인: 같은 이름과 매개변수(float)를 가진 메서드가 중복 정의됨
  • 조치: 메서드 이름을 RestoreHealth, RecoverHunger 등으로 명확히 변경
public void RestoreHealth(float amount) { ... }
public void RecoverHunger(float amount) { ... }

✍️ 코딩 시 메서드 명명은 시그니처와 함께 유일성을 유지해야 한다는 원칙 체득


🎯 오늘의 키워드

  • 상태 시스템 디버깅
  • UI 자동 정렬 레이아웃
  • 코드 안정화와 예외 방지 습관
  • 생산성 도구 (정렬, 탐색, 정리) 체득
  • 메서드 충돌 실습 통한 시그니처 관리 능력 향상

🧠 2025 Unity 3D 입문 기술노트 (이론 중심)

🌌 Skybox (스카이박스)

 

✔️ 개념 요약

  • 3D 씬의 배경을 구성하는 큐브 형태 또는 구형의 텍스처 맵핑 기법
  • 플레이어 시점에서 주변 환경 전체를 감싸며 하늘, 구름, 별, 안개 등 자연적 요소를 표현
  • 주로 큐브맵(6면) 또는 프로시저럴(Procedural) 방식으로 구성

✔️ 종류

종류 설명

Skybox/6 Sided 전통적인 큐브 형태. 6개의 텍스처로 구성된 정육면체 맵
Skybox/Cubemap 하나의 큐브맵 텍스처를 이용하는 포맷 (모바일에서 효율적)
Skybox/Procedural 시간, 태양 위치 등을 반영해 자동 계산되는 동적 스카이박스 (Day/Night 효과에 유리)

✔️ 설정 위치

  • Window > Rendering > Lighting > Environment > Skybox Material
  • 또는 코드로 설정:
RenderSettings.skybox = yourSkyboxMaterial;

✔️ 특징 및 팁

  • 카메라가 이동해도 Skybox는 고정되어 시점을 유지 → 몰입감 ↑
  • 환경광 조명, 반사 광에도 간접적으로 영향 (특히 Reflection Probe와 연계 시)
  • 고해상도 Skybox는 퍼포먼스에 영향을 줄 수 있어, 모바일 플랫폼에서는 간단한 Cubemap 추천

🧲 Rigidbody & ForceMode

✔️ Rigidbody 개요

  • Unity의 물리 엔진을 사용하는 모든 물리 기반 오브젝트의 핵심 컴포넌트
  • 중력, 힘, 토크, 질량, 속도 등 다양한 물리 속성 보유
  • 게임 내 물리 충돌, 중력 낙하, 발사체, 점프 등 구현의 중심

✔️ Rigidbody 주요 설정 항목

속성 설명

Mass 질량. 가속도 및 충돌 반응에 영향
Drag / Angular Drag 선형/회전 감속 (마찰과 비슷한 역할)
Use Gravity 중력 사용 여부 (떨어지는 물체인지 여부 설정)
Is Kinematic 물리 엔진에 영향을 받지 않게 함 (스크립트 이동 전용 객체에 적합)
Interpolate 카메라 떨림 방지를 위한 부드러운 위치 보간 방식

✔️ ForceMode 종류 (AddForce의 두 번째 인자)

ForceMode 효과 사용 예

Force 질량 기반 지속적인 힘 풍압, 지속 가속
Acceleration 질량 무시. 순수 가속도 무중력 상태 추진
Impulse 질량 기반 짧고 강한 힘 점프, 피격 반동
VelocityChange 질량 무시. 속도 변경 순간 회피, 대쉬
rb.AddForce(Vector3.forward * 10f, ForceMode.Impulse);

✔️ 참고 사항

  • Force와 Impulse는 질량에 영향을 받음
  • VelocityChange와 Acceleration은 질량을 무시함
  • 타격감이 중요한 경우 → Impulse 추천
  • 대쉬, 텔레포트 느낌 → VelocityChange

🔦 Ray & Raycast

✔️ Ray란?

  • **시작점(origin)**과 **방향(direction)**을 가진 보이지 않는 선 (일종의 레이저 포인터)
  • Unity에서 광선처럼 사용하여 충돌 대상을 탐색하거나 위치를 지정하는 데 사용

✔️ Raycast란?

  • Ray를 발사하여 일정 거리 내에서 오브젝트와 충돌하는지를 검사하는 방식
  • Physics.Raycast()로 구현하며, UI를 제외한 물리 오브젝트 검사에 사용

✔️ 사용 예시

Ray ray = new Ray(transform.position, transform.forward);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 100f))
{
    Debug.Log("Hit object: " + hit.transform.name);
}

✔️ 활용 사례

  • 총알 맞은 오브젝트 체크
  • 마우스 클릭 대상 확인 (카메라.ScreenPointToRay 사용)
  • NPC 시야, 감지 시스템
  • 조준 보조 시스템 (중심선 기반 타겟팅)

✔️ RaycastHit 주요 정보

속성 설명

.point 충돌 지점의 위치
.transform 맞은 대상의 Transform
.distance 충돌까지의 거리

⚠️ Raycast는 기본적으로 Collider가 붙은 물체에만 반응함. 레이어 마스크를 사용해 검사 범위 조절 가능.

 


⌨️ Unity Input System (신 입력 시스템)

✔️ 개요

  • Unity의 최신 입력 시스템 (Input System Package)
  • 기존 Input.GetKey 또는 Input.GetAxis 방식보다 구조화되어 있음
  • 키보드, 마우스, 터치, 게임패드 등 다양한 입력 장치를 Action 기반으로 통합 관리

✔️ 주요 구성 요소

구성 설명

Input Actions Asset .inputactions 파일로, 모든 입력을 구조화하여 정의
InputActionMap 특정 상태/상황별로 묶은 입력 세트 (예: Player, UI)
InputAction 실제 키 동작을 정의하는 단위 (Jump, Move 등)
Binding 어떤 키/버튼이 InputAction과 연결되는지 설정

✔️ 주요 이벤트 흐름

  • started : 키를 누르기 시작할 때
  • performed : 입력이 인식되었을 때 (ex. 누르고 있음)
  • canceled : 입력이 해제될 때 (ex. 키를 뗐을 때)
public void OnJump(InputAction.CallbackContext context)
{
    if (context.performed)
    {
        Jump();
    }
}

✔️ 처리 방식 3종 비교

방식 개요 장점 단점

SendMessage "On+이름" 메서드를 자동 호출 간단함, 자동 연결 느리고 디버깅 어려움
Invoke UnityEvent 인스펙터에서 연결 디자이너 친화적 실수 시 런타임 에러, 성능 낮음
C# Event 바인딩 코드에서 직접 연결 성능 좋고 명확 구현 구조를 정확히 이해해야 함

✔️ PlayerInput 컴포넌트 설정

  • Input Actions를 연결하면 자동으로 이벤트 방식 선택 가능 (SendMessage / InvokeUnityEvent / C# Events)
  • Behavior 설정에서 선택 가능:
    • Invoke Unity Events
    • Send Messages
    • Invoke C# Events

✔️ Input System의 장점

  • 여러 플랫폼 입력을 하나의 인터페이스로 처리
  • 입력 방식 간 전환이 쉬움 (키보드 → 패드 → 모바일)
  • 멀티 키 바인딩, 디바이스 인식 자동 처리 가능
  • 런타임 중 입력 스킴 전환 가능

🖱️ Scroll View & UI 자동 배치 시스템

✔️ Scroll View란?

  • Unity UI 시스템에서 스크롤 가능한 영역을 제공하는 컨테이너 컴포넌트
  • 내부 콘텐츠가 뷰포트를 넘어설 경우 자동으로 스크롤바 생성
  • 주로 리스트, 인벤토리, 로그창, 대화창 등에 사용됨

✔️ 구성 요소 구조

Scroll View (스크롤 전체)
├── Viewport (보여지는 화면 영역)
│   └── Content (실제 콘텐츠들)
└── Scrollbar (세로/가로 선택적)
  • Viewport: 마스크 역할. 이 영역 바깥의 콘텐츠는 보이지 않음
  • Content: 이 안에 Vertical Layout Group 등으로 버튼/텍스트 정렬
  • Scrollbar: 자동 활성화되거나 수동으로 배치 가능

✔️ 필수 조합 컴포넌트

컴포넌트 역할

Vertical/Horizontal Layout Group 자식 UI 요소들을 자동으로 세로/가로 정렬
Content Size Fitter 콘텐츠의 크기를 자식 요소에 맞게 자동 조절
Layout Element 자식 요소 각각의 사이즈/우선순위 세부 조정 가능

✔️ 일반적인 설정 흐름

  1. Scroll View 생성 → 내부 구조 그대로 유지
  2. Content에 Vertical Layout Group + Content Size Fitter 추가
  3. 버튼, 텍스트, 슬롯 등 요소들을 Content의 자식으로 추가

🧠 왜 중요한가?

  • 콘텐츠 개수가 달라져도 자동으로 배치됨 → UI 제작 시간 감소
  • 디바이스 해상도가 달라져도 대응 가능 → 반응형 디자인
  • 런타임 중 버튼 추가/삭제가 빈번한 UI에서 유지보수성이 매우 뛰어남

✔️ 예제: 동적으로 버튼 추가

GameObject btn = Instantiate(buttonPrefab, contentTransform);
btn.GetComponentInChildren<Text>().text = "New Option";

이때도 Vertical Layout Group이 잡혀 있으면 자동으로 위치가 맞춰짐

⚠️ 주의 사항

  • Content Size Fitter를 사용할 경우 스크롤뷰와 충돌하는 경우가 있음
    → Layout Group과 함께 쓰되, Content의 RectTransform anchor/pivot 조정 필수
  • 모바일 UI에서는 스크롤바보다 터치 스크롤 감도 조절이 중요

🖱️ UI Event System & Graphic Raycaster

✔️ UI Event System이란?

  • Unity에서 **UI 상호작용(클릭, 드래그, 포커스 등)**을 처리하기 위한 이벤트 처리 시스템
  • UI뿐 아니라 모든 입력 기반 트리거의 핵심 관리자 역할을 함

✔️ 구성 요소

구성 요소 설명

EventSystem 씬에 하나만 존재. 모든 UI 입력 이벤트를 처리하는 중심 객체
Standalone Input Module 마우스/키보드 입력 처리용. 기본 모듈
Input System UI Module 신 Input System 기반의 UI 입력 처리용 모듈 (입력 시스템을 설정한 경우 자동 사용됨)
Graphic Raycaster Canvas 상에서 어떤 UI 요소가 클릭되었는지 감지하는 컴포넌트

✔️ 작동 흐름 요약

  1. 사용자가 마우스 클릭 or 터치 입력
  2. EventSystem이 입력을 감지
  3. Canvas 상에 붙은 Graphic Raycaster가 UI 요소에 Raycast를 쏴서 클릭된 오브젝트 탐색
  4. 클릭된 오브젝트에 연결된 인터페이스 함수 실행 (예: IPointerClickHandler)

🎮 자주 사용하는 인터페이스

인터페이스 설명

IPointerClickHandler 클릭 시 동작
IPointerEnterHandler 마우스를 올렸을 때 동작
IPointerExitHandler 마우스가 벗어날 때 동작
IDragHandler 드래그 중 동작
IDropHandler 드래그 놓기 동작
using UnityEngine.EventSystems;

public class MyButton : MonoBehaviour, IPointerClickHandler
{
    public void OnPointerClick(PointerEventData eventData)
    {
        Debug.Log("버튼 클릭됨!");
    }
}

💡 유니티의 UI 버튼은 실제로 Button 클래스 내부에서 이 인터페이스들을 구현하고 있음


✅ Graphic Raycaster의 역할

  • Canvas에 부착되며, UI 요소에 Ray를 쏘아 감지
  • LayerMask를 통해 감지할 UI의 레이어를 제한할 수 있음
  • Physics Raycaster와 달리, UI 전용 Raycast임 (3D 물체 탐지는 해당 안 됨)

⚠️ 주의 사항

  • UI가 Canvas의 하위에 있어야 Raycast 감지가 가능
  • Canvas가 World Space일 경우, 카메라 설정이 정확해야 Ray 감지가 동작
  • UI에 Raycast Target이 꺼져 있으면 클릭 불가 (예: 투명 이미지 등)

💡 팁: Physics.Raycast와의 차이

항목 UI Raycast (Graphic Raycaster) 물리 Raycast (Physics.Raycast)

대상 UI 요소 (Image, Button 등) Collider가 붙은 3D/2D 오브젝트
감지 방식 Canvas 기준 UI Ray 투사 실제 공간에 직선 광선 투사
필요 조건 Canvas + GraphicRaycaster + EventSystem Collider + Rigidbody 등

⏱️ Time.deltaTime과 Update 루프 개념

✔️ Time.deltaTime이란?

  • **이전 프레임과 현재 프레임 사이에 걸린 시간(초)**을 의미
  • 매 프레임마다 값이 변하며, 프레임 속도에 따라 일정하지 않음
  • 주로 이동, 회전, 상태 감소 등 프레임 기반 계산을 보정하기 위해 사용
transform.Translate(Vector3.forward * speed * Time.deltaTime);

→ 매초 speed만큼 이동하게 보정됨

✔️ 왜 중요한가?

  • Unity는 기본적으로 프레임 단위로 Update()를 실행
  • 하지만 프레임이 60FPS일 때와 30FPS일 때는 같은 코드라도 속도가 달라짐
  • deltaTime을 곱해주면 프레임에 관계없이 일정한 속도로 움직이거나 변화함

🧠 쉽게 말하면: “초당 얼마나 움직일지를 프레임 수에 따라 자동 보정해주는 값”


🔁 Unity의 주요 루프 구조

✅ Update()

  • 매 프레임마다 호출되는 함수 (1초에 60프레임이면, 60번 호출됨)
  • 입력 처리, 상태 변화, 실시간 연산 등 대부분의 로직은 여기에 작성
void Update()
{
    MovePlayer();
    RotateEnemy();
}

✅ FixedUpdate()

  • 물리 계산용 전용 루프 (기본적으로 0.02초마다 실행 = 50FPS 고정)
  • Rigidbody 움직임이나 충돌 처리 등은 여기에서 실행해야 예측 가능함
void FixedUpdate()
{
    rb.AddForce(force);
}

✅ LateUpdate()

  • 모든 Update() 호출 후 실행
  • 주로 카메라 이동, UI 동기화 등 오브젝트가 이동된 후 처리할 때 사용

💡 Update 루프 선택 기준

함수 사용 목적 비고

Update() 키 입력, 상태 처리, UI 갱신 등 Time.deltaTime 사용 필요
FixedUpdate() 물리 힘 적용, Rigidbody 제어 deltaTime 대신 fixedDeltaTime 내장됨
LateUpdate() 카메라, 따라가기, 정렬 등 순서상 마지막 실행됨

🧠 요약 비유

  • Update() → 실시간 사용자 입력 & 상태 변화
  • FixedUpdate() → 일정한 틱으로 움직이는 기계
  • LateUpdate() → 마지막에 따라붙는 카메라맨

🧩 Component vs GameObject vs MonoBehaviour 구조

✔️ GameObject란?

  • Unity의 씬 상에 존재하는 모든 오브젝트의 기본 단위
  • GameObject 그 자체는 아무런 기능이 없음 → Component들을 조합해 기능 부여
  • 트랜스폼(위치/회전/크기), 메쉬, 콜라이더, 스크립트 등은 모두 컴포넌트로 붙음
GameObject player = new GameObject("Player");

✔️ Component란?

  • GameObject에 붙는 기능 단위 조각
  • Transform, Rigidbody, Collider, AudioSource, Script 등 전부 Component
  • GameObject에 여러 Component를 붙여서 완성된 기능의 오브젝트를 만듦
player.AddComponent<Rigidbody>();

Unity 구조의 핵심 철학: 모든 동작은 Component의 조합이다.


✔️ MonoBehaviour란?

  • Unity의 모든 사용자 정의 스크립트가 상속받는 기본 클래스
  • Update(), Start(), OnTriggerEnter() 등 Unity 생명주기를 사용할 수 있게 해줌
  • 반드시 GameObject에 붙어야 동작함
public class PlayerController : MonoBehaviour
{
    void Update()
    {
        Move();
    }
}
  • MonoBehaviour는 자체적으로 new 생성이 불가능하고, 반드시 GameObject에 AddComponent로 추가되어야 함

🔄 관계 정리

GameObject
├── Transform (항상 존재)
├── Rigidbody (Component)
├── BoxCollider (Component)
└── PlayerController (MonoBehaviour Script → Component)
  • GameObject: 껍데기
  • Component: 기능 조각
  • MonoBehaviour: 사용자 정의 기능을 만들기 위한 Component 기반 클래스

🎯 실전 예시

GameObject enemy = GameObject.Find("Enemy");
Rigidbody rb = enemy.GetComponent<Rigidbody>();
  • Find()로 GameObject를 찾고
  • GetComponent<T>()로 붙어있는 기능을 찾아 가져옴

🧠 요약 정리

개념 설명

GameObject 씬 위의 존재 단위 (비어있는 틀)
Component GameObject에 부착되는 기능 모듈 (조각)
MonoBehaviour Unity의 사용자 스크립트 기반 클래스 (컴포넌트로 동작)

🎓 “GameObject는 컨테이너, Component는 기능, MonoBehaviour는 우리가 직접 만드는 기능 컴포넌트”


🎞️ Animation과 Animator Controller 구조

✔️ Animation과 Animator 차이

용어 역할

Animation Clip 실제 애니메이션 데이터 (ex: 달리기, 점프, 피격 등)
Animator Controller 여러 애니메이션 클립을 상태(State)로 구성하고 전환(Transition) 제어
Animator GameObject에 붙는 컴포넌트. Animator Controller를 받아 실행 담당

✅ 구성 요소 예시

Player (GameObject)
├── Animator (Component)
└── Animator Controller (에셋)
      ├── Idle (Animation Clip)
      ├── Run (Animation Clip)
      └── Jump (Animation Clip)
  • Animator → 씬에서 동작
  • Animator Controller → 클립을 묶어 로직 제어
  • Animation Clip → 실제 움직임 데이터

🎮 Animator Controller의 핵심 구조

  • State Machine 기반
  • 각 상태(State)에 Animation Clip이 연결됨
  • 상태 간 전환(Transition)은 **조건(Condition)**을 기반으로 이루어짐

예: 상태 전환 흐름

Idle → [조건: Speed > 0.1] → Run
Run → [조건: IsJump == true] → Jump
Jump → [조건: Grounded == true] → Idle

✔️ Transition 조건 설정

  • Animator Controller에서 파라미터(Parameter)를 정의하고
  • 상태 전환에 조건으로 사용함

파라미터 종류

유형 설명

Float 이동 속도 등 연속적인 값
Bool 점프 중 여부, 피격 여부 등
Int 상태 구분용 정수 값
Trigger 한 번만 발동되는 이벤트 (ex: 공격)

✍️ 스크립트에서 Animator 제어

Animator anim = GetComponent<Animator>();

// bool 타입 파라미터 설정
anim.SetBool("IsJump", true);

// Trigger 발동
anim.SetTrigger("Attack");
  • Animator 파라미터의 이름은 정확히 일치해야 함 (오타 주의)

🧠 애니메이션 동기화 팁

  • Root Motion 사용 시 → 애니메이션이 이동/회전을 포함함
  • Root Motion 비활성화 시 → Transform 이동은 스크립트로 제어

📌 캐릭터 조작이 중심이면 Root Motion Off + 코드 기반 이동
📌 Cutscene/전용 연출이면 Root Motion On 사용 가능


🏷️ Unity Tag vs Layer 차이 정리

✔️ Tag란?

  • 오브젝트에 **의미 있는 이름표(Label)**를 붙이는 기능
  • 오브젝트 간의 구분, 조건 탐색, 충돌 식별 등에 사용됨
  • 예시: Player, Enemy, Item, Checkpoint

✅ Tag 특징

  • 문자열 기반
  • 태그는 여러 오브젝트가 공유할 수 있음
  • CompareTag() 또는 tag 속성으로 코드에서 판별
if (other.CompareTag("Enemy"))
{
    TakeDamage();
}

✅ Tag 설정 방법

  • 오브젝트 선택 > Inspector > Tag > Add Tag... 에서 사용자 정의 가능

🧱 Layer란?

  • 카메라/물리 시스템이 인식하는 필터 레이어
  • 충돌 감지, 카메라 렌더링, 레이캐스트 대상 설정 등에 사용됨
  • 숫자 기반 인덱스를 가지며, 총 32개까지 설정 가능 (0~31)

✅ Layer 특징

용도 설명

카메라 Culling Mask 특정 Layer만 렌더링 여부 설정
Raycast 특정 Layer에만 반응할 수 있도록 설정
Physics 충돌 매트릭스 Edit > Project Settings > Physics 에서 충돌 여부 설정
int layerMask = 1 << LayerMask.NameToLayer("Enemy");
if (Physics.Raycast(ray, out hit, 100f, layerMask))
{
    Debug.Log("Enemy 감지됨");
}

✅ Layer 설정 방법

  • Inspector > Layer > Add Layer... 에서 사용자 정의
  • 이후 오브젝트에 해당 Layer를 할당

🔄 Tag vs Layer 요약 비교

구분 Tag Layer

목적 구분/식별 충돌/렌더링 필터링
데이터 형태 문자열 숫자 인덱스 (최대 32개)
설정 위치 Inspector > Tag Inspector > Layer
코드 사용 CompareTag("Player") LayerMask, gameObject.layer 등
중복 사용 가능 (여러 오브젝트에 동일 태그 가능) 단일 오브젝트당 하나의 레이어

🧠 Tag는 ‘이름표’, Layer는 ‘필터링 도구’라고 생각하면 이해 쉬움


🔗 Unity 오브젝트 참조 방식 요약

Unity에서는 코드에서 특정 오브젝트나 컴포넌트를 참조하기 위해 여러 가지 방법이 존재합니다.
상황에 따라 적절한 방법을 선택하면 코드 유지보수성과 성능이 크게 향상됩니다.


✅ 1. GetComponent<T>()

  • 현재 GameObject 또는 자식 오브젝트에서 컴포넌트를 가져옴
  • 가장 기본적이며 자주 쓰이는 방식
Rigidbody rb = GetComponent<Rigidbody>();

⚠️ 성능을 고려해 Start()나 Awake()에서 캐싱하는 것이 좋음


✅ 2. GameObject.Find()

  • 씬 안의 GameObject를 이름(String)으로 찾아줌
  • 사용은 간단하지만, 느리고 의존성이 높기 때문에 자주 사용하지 말 것
GameObject player = GameObject.Find("Player");

❌ 오타 발생 시 런타임 오류, 비효율적인 탐색 구조


✅ 3. transform.Find()

  • 현재 오브젝트의 자식 중에서 이름으로 탐색
  • 구조가 정해진 경우에는 유용함
Transform hand = transform.Find("Hand_R");

✅ 4. FindObjectOfType<T>()

  • 씬 내에서 특정 타입의 첫 번째 오브젝트를 찾아 반환
  • 단일 매니저, Singleton 참조에 많이 사용됨
GameManager gm = FindObjectOfType<GameManager>();

⚠️ 실행 중 호출하면 성능 저하 가능 → Start나 Awake에서 1회만 호출


✅ 5. public 필드 + 인스펙터 할당

  • 가장 안전하고 직관적인 방법
  • 오브젝트나 컴포넌트를 Drag & Drop으로 할당
public GameObject weapon; // 인스펙터에서 직접 연결

✅ 가장 권장되는 방식 (수동 설정이 가능할 때)


✅ 6. SerializeField + private

  • 외부 접근은 막으면서 인스펙터 노출 가능
[SerializeField] private PlayerController controller;

✅ 캡슐화와 인스펙터 편집을 모두 만족


✅ 7. Singleton 패턴으로 접근

  • 전역에서 접근이 필요한 매니저 계열 객체에 사용
public class GameManager : MonoBehaviour
{
    public static GameManager Instance { get; private set; }

    private void Awake()
    {
        Instance = this;
    }
}

// 접근 예시
GameManager.Instance.DoSomething();

🧠 요약 정리

방식 용도 특징

GetComponent<T>() 내 컴포넌트 참조 가장 기본적. 캐싱 권장
GameObject.Find() 이름으로 찾기 비효율적. 지양
FindObjectOfType<T>() 타입으로 찾기 매니저 참조에 용이
Inspector 연결 수동 연결 가장 안전하고 직관적
Singleton 전역 접근 매니저, UI 컨트롤에 적합

🔄 Unity Script 실행 순서 및 초기화 흐름

Unity에서는 스크립트의 생명주기(Lifecycle)가 정해져 있으며, 특정 함수들은 정해진 순서와 타이밍에 따라 호출됩니다.
이를 이해하면 객체 초기화, 물리 처리, 사용자 입력 반영 등을 정확한 타이밍에 구현할 수 있습니다.


✔️ 주요 실행 순서 요약

순서 함수 설명

Awake() 스크립트가 활성화될 때 가장 먼저 실행. 오브젝트 간 참조 설정에 적합
OnEnable() 오브젝트가 활성화될 때 호출. 매번 Enable 시마다 실행됨
Start() 첫 프레임 직전 한 번만 호출. 초기화 작업에 주로 사용
Update() 매 프레임마다 실행. 입력 처리, 상태 갱신 등
LateUpdate() 모든 Update 후 실행. 카메라 추적 등에 사용
FixedUpdate() 고정된 시간 간격으로 실행. 물리 연산용
OnDisable() 오브젝트 비활성화될 때 호출
OnDestroy() 오브젝트가 파괴되기 직전 호출

✅ 실행 순서 흐름 예시

Awake()
→ OnEnable()
→ Start()
→ Update() / FixedUpdate() (반복)
→ OnDisable()
→ OnDestroy()

🧠 함수별 주요 역할

함수 주로 사용하는 목적

Awake() 스크립트 내부 변수 초기화, 싱글턴 설정 등
Start() 외부 참조 초기화 (다른 오브젝트가 Awake한 뒤 실행됨)
Update() 실시간 입력 처리, 상태 변화 등
FixedUpdate() Rigidbody 이동/힘 적용 등 물리 처리
LateUpdate() 카메라 따라가기, 위치 동기화 등
OnEnable() 씬 재시작, UI 리셋 등에 활용 가능
OnDestroy() 데이터 저장, 종료 처리 등 정리 로직에 사용

📝 실습 팁

  • 싱글턴은 대부분 Awake()에서 Instance = this로 설정
  • 오브젝트 간 의존성이 있을 때는 Start()에서 참조 연결
  • FixedUpdate()는 프레임률에 관계없이 일정 간격 → Time.deltaTime 사용 ❌

⚠️ 주의 사항

  • 비활성화된 오브젝트는 Start(), Update()가 호출되지 않음
  • Awake()는 오브젝트가 비활성화여도 호출됨 (단, 비활성 상태에서 Instantiate한 경우)

📦 ScriptableObject란? 구조와 활용

✔️ ScriptableObject 개념

  • Unity에서 제공하는 데이터 중심 객체 생성용 클래스
  • 일반 MonoBehaviour와 다르게 씬에 존재하지 않고, Hierarchy에 붙지 않음
  • 프로젝트 내에 에셋으로 존재하며, 공유 가능한 데이터 템플릿 역할
[CreateAssetMenu(fileName = "NewStat", menuName = "Custom/StatData")]
public class StatData : ScriptableObject
{
    public string characterName;
    public int maxHealth;
    public float moveSpeed;
}

✅ 생성 방법

  1. ScriptableObject를 상속받는 클래스를 정의
  2. [CreateAssetMenu] 어트리뷰트로 생성 메뉴에 노출
  3. Project 창에서 우클릭 > Create > Custom/StatData로 생성

🎯 주요 특징

항목 설명

독립성 씬에 존재하지 않음. Hierarchy에 붙지 않음
참조 가능성 여러 오브젝트가 하나의 ScriptableObject를 참조 가능
사용 예 스탯 템플릿, 아이템 정보, 설정값, 테이블 데이터 등
변경 반영 ScriptableObject를 수정하면 이를 참조한 모든 오브젝트가 반영됨

🎮 캐릭터의 스탯, 무기 속성, 대사 데이터 등 반복되는 구조를 공유할 때 매우 유리


🧪 예제: 무기 데이터 활용

public class Weapon : MonoBehaviour
{
    public WeaponData weaponData;

    void Start()
    {
        Debug.Log(weaponData.damage);
    }
}
[CreateAssetMenu(menuName = "Data/Weapon")]
public class WeaponData : ScriptableObject
{
    public string weaponName;
    public int damage;
    public float cooldown;
}
  • ScriptableObject는 Project 창에서 직접 만들고, MonoBehaviour에 드래그로 할당

💡 MonoBehaviour vs ScriptableObject

구분 MonoBehaviour ScriptableObject

목적 씬 내 동작, 컴포넌트 데이터 템플릿, 공유 리소스
저장 위치 Hierarchy Project 창 (Asset)
인스턴스화 Instantiate 필요 CreateInstance or Asset 생성
실행 흐름 Update 등 생명주기 포함 Update 없음 (데이터 전용)

🧠 활용 팁

  • 변하지 않는 설정값, 수치 데이터, 반복 구조에는 ScriptableObject가 훨씬 효율적
  • 씬을 넘어서는 데이터 유지가 필요할 때 적합
  • 단, 런타임 변경사항은 저장되지 않음 → 저장 기능이 필요하면 JSON이나 PlayerPrefs와 병행

📓 Unity 입문 백지 학생 메모장

공식 튜터님도 알려주셨고, 강의도 많지만... 지금 머릿속은 혼란 그 자체.


🤯 지금까지 배운 게 너무 많아요

  • Skybox가 뭐였는지 기억 안 남
  • Rigidbody ForceMode 4개 중 뭐가 뭔지 헷갈림
  • Scroll View가 자동 정렬된다는 건 알겠는데, 설정법은 벌써 까먹음
  • Animation은 상태 머신이라는데… 내 머리는 스택 머신 상태

😵 헷갈리는 것들 예시

개념나의 혼란

deltaTime 왜 곱하는지 알 것 같으면서도 모르겠음
Tag vs Layer 아직도 충돌에 뭐 쓰는지 햇갈림
GetComponent 이거 자주 쓰는데 캐싱 안 하면 왜 느린지도 감 못 잡음

🧠 하지만 정리는 된다

  • 지금 당장은 이해보다는 반복이 필요하다
  • 하나씩 직접 해보면 몸이 기억함
  • “몰라도 일단 써본다”는 태도로 접근 중

✍️ 나의 전략

  • 💡 하나하나 예제로 정리해서 실습 코드 옆에 붙이기
  • 🧩 모르는 개념은 바로바로 주석으로 메모
  • 🐌 진도는 느려도, 실전 적용되면 오래 간다

👣 지금은 아직 백지 상태지만, 이 백지는 곧 설계도로 바뀐다. 그 첫 벽돌은 “포기하지 않고 하나씩 쌓는 습관”