게임프로그래밍/Unity_C#

[멋쟁이사자처럼부트캠프] 유니티 게임 개발 5기(2025.06.23-2025.06.27)

shine94 2025. 6. 30. 05:39

해당 글은 유니티 게임 개발 수업 후 정리한 글입니다

   https://bootcamp.likelion.net/school/kdt-ugm-5th

 

유니티 게임 개발 5기 : 멋사 부트캠프

개발부터 출시까지! 나만의 게임을 세상에 선보이는 유니티 부트캠프

bootcamp.likelion.net

 

 

 

 

* Update()

   일반적인 작업용

   이동 작업을 transform으로 직접 조작할 경우 여기서 처리하나,

   이 방식은 프레임 스킵이 발생하면 그만큼 렌더링이 지연되어 지연되고,

   지연된 만큼 한 번에 이동되기 때문에 순간이동처럼 보일 수 있다

   또, transform으로 이동하는 경우, 물리 엔진을 거치지 않아 충돌 감지가 발생하지 않는다

 

   [🤔 그럼 여기서 물리엔진 계산하면 되잖아]

   물리 엔진은 고정된 시간 간격(Fixed Timestep)으로 계산된다

   대부분 Update 속도가 훨씬 빠르며,

   프레임마다 속도를 갱신하지만, 물리 엔진이 아직 계산을 반영하기 전 상태에서 덮어쓰게 되므로

   이로 인해 이동 타이밍과 충돌 판정 타이밍이 엇갈리면서, 불안정한 움직임, 충돌 처리 누락, 끊김 등이 발생할 수 있다


* FixedUpdate()

   물리 연산 작업용

   Rigidbody를 이용한 물리 기반 작업은 여기서 처리하지 않으면 연산 타이밍이 꼬일 수 있다

 

   [❓ Why]

   물리 엔진은 고정된 시간 간격으로 계산하기 때문이다

 

* 최종적인 결론

   입력은 Update에서

   물리 엔진을 이용한 이동은 FixedUpdate에서

float input;

void Update()
{
	// 입력은 Update에서
	input = Input.GetAxisRaw("Horizontal");
}

void FixedUpdate()
{
	// 이동은 FixedUpdate에서
	rb.velocity = new Vector2(input * speed, rb.velocity.y);
}

 

* 타일맵(Tilemap)

   이미지를 작은 타일로 나눠 격자 형태로 배치해서, 큰 배경이나 맵을 효율적으로 구성하는 방식

   큰 배경 이미지를 통째로 가져가면 메모리 부담이 크지만,

   작은 이미지를 반복해서 배치하면 동일한 리소스를 재사용하게 되므로 빌드 용량이 훨씬 가벼워진다

   그 결과, 컴파일과 빌드 시간도 줄일 수 있다

 

* 타일 팔레트(Tile Palette)

   타일맵 작업을 위해, 타일 이미지를 마치 물감을 팔레트에 올려두듯 정리해 놓는 도구

   필요한 타일을 여기서 선택해서 씬에 배치할 수 있도록 도와준다

 

   Window > 2D > Tile Palette

 

* Tilemap Collider 2D

   타일맵마다 개별적인 Collider를 자동 생성해주는 컨포넌트

   타일 하나마다 Collider가 생성되므로 경계선이 많아지고, 그로 인해 물리 연산이 비효율적이다

 

* Composite Collider 2D

   여러 개의 Collider를 하나의 커다란 콜라이더로 합쳐주는 최적화 도구

   성능 향상과 충돌 경계 단순화를 위해 자주 사용되며, Tilemap Collider 2D와 함께 쓰인다

 

   [Edge Radius]

   Collider 외곽선의 가장자리를 부드럽게 둥글리는 정도를 나타낸다

   값이 클수록 둥글게 처리되어, 이동 가능한 영역이 그만큼 줄어든다

 

* Rigidbody 2D(Static 설정)

   정적인 지형용으로 적절한 설정이며, 물리 시뮬레이션 전에 Collider를 미리 생성해두는 방식

   즉, 런타임 중에 계산하지 않고, 씬 실행 시점에 이미 계산돼 있어서 성능에 유리하다

   Composite Collider를 쓰려면 반드시 Rigidbody 2D가 필요하며, 이때는 Static 설정을 쓰는 게 일반적이다

 

* 지금 공부하고 있는 방식은 상하좌우 이동만 가능한 2D 캐릭터 조작 게임으로, 중력이나 회전이 필요하지 않음

 

   [따라서]

   물리 엔진에서 중력을 0으로, Freeze Rotation의 Z축을 체크하여 안정적인 이동 구현 가능

 

   [만약 중력과 회전이 있다면]

   중력에 의해 콜라이더의 둥근 곡면을 따라 미끄러지거나, 충돌 시 회전이 발생해 구르는 듯한 동작이 나타난다

   둥근 곡면이 없더라도 충돌 시 물리 회전이 적용되어 기울어지거나 옆으로 눕는다

 

* 유니티의 UI 이벤트 시스템 인터페이스

   UI 오브젝트나 Collider가 붙은 GameObject에서만 이벤트가 발생하며,

   반드시 EventSystem과 Raycaster 구성 필요

 

   [정리]

   UI 오브젝트인 경우

   - EventSystem

   - Canvas + GraphicRaycaster

 

   Collider가 붙은 GameObject(2D 기준)

   - EventSystem

   - Physics2DRaycaster

 

(1) IPointerDownHandler

   마우스 버튼 또는 터치가 눌렸을 때 호출됨

void OnPointerDown(PointerEventData eventData)

 

(2) IDragHandler

   마우스 또는 터치를 누르고 움직일 때(= 드래그) 호출됨

void OnDrag(PointerEventData eventData)

 

(3) IPointerUpHandler

   마우스 버튼 또는 터치가 떼어졌을 때 호출됨

void OnPointerUp(PointerEventData eventData)

 

* 조이스틱 방향 벡터 코드

// direction1(방향 + 거리 포함) → 정규화 안된 상태
var dragDirection = _currPosition - _startPosition;

 

https://shine94.tistory.com/462

 

[Unity] 수학과 Unity 관점에서 벡터와 스칼라 정리

* 수학에서의 백터와 스칼라 (1) 스칼라(Scalar) 크기만 갖는 값 (예) 5m, 섭씨 20도, 256바이트, 4000 칼로리 (2) 벡터(Vector) 크기 + 방향을 갖는 값 (예) 30m/초 동쪽, 약 5마일 북쪽, 힘, 가속도 [정리하자면

shine94.tistory.com

 

* magnitude 

   벡터의 길이(방향은 무시됨)

 

* normalized

   방향만 유지하고 길이를 1로 만든 벡터

 

* 조이스틱 드래그 방향 처리 코드

public void OnPointerDown(PointerEventData eventData)
{
    _startPosition = eventData.position;
}

public void OnDrag(PointerEventData eventData)
{
    _currPosition = eventData.position;
    var dragDirection = _currPosition - _startPosition;

    // distance : 거리
    // +75f, -75f : X/Y축 조이스틱 입력의 최대값(조이스틱 범위 제한)
    var maxDistance = Mathf.Min(dragDirection.magnitude, 75f);

    // _startPosition : 조이스틱 원래 위치
    // dragDirection.normalized * maxDistance : 드래그 방향값 * 최대 거리 75f
    handlerUI.transform.position = _startPosition + dragDirection.normalized * maxDistance;
}

public void OnPointerUp(PointerEventData eventData)
{
    // 드래그 종료 시 조이스틱 핸들 위치 초기화
    handlerUI.transform.position = Vector2.zero;
}

 

조이스틱 UI 구성 및 설정 경로

   Canvas > Joystick(빈 오브젝트) > Background(조이스틱 배경) > Handle(방향 표시 이미지)

   ㄴ Joystick(빈 오브젝트)의 Image 컴포넌트는 투명도 0으로 설정해야 함

 

* ForceMode2D

(1) Force

     지속적으로 작용하는 힘(Continuous Force)

     FixedUpdate마다 누적 적용되어 속도를 점점 증가시키는 가속도

    (예) 바람, 물살처럼 꾸준히 밀어내는 힘

rigidbody2D.AddForce(Vector2.right * 10f, ForceMode2D.Force);

     이 경우, FixedUpdate마다 10만큼의 가속도가 누적되어 점점 빨라진다

 

(2) Impulse

     순간적인 충격(Instantaneous Impulse)

     한 순간에 속도를 즉시 변화시키는 힘

     점프, 충돌, 폭발처럼 짧고 강한 충격을 줄 때 사용

rigidbody2D.AddForce(Vector2.up * 10f, ForceMode2D.Impulse);

     이 경우, 한 번만 힘이 적용되며 질량에 따라 속도 변화량이 결정된다

                  FixedUpdate 마다 반복 적용되지 않고, 딱 한 번 즉시 작용된다

 

* 애니메이션 블렌딩 시 실수했던 점

   처음에 2D Simple Directional을 선택했는데, 이 블렌드 타입은 방향 값이 180도 이상인 경우를 처리할 수 없다

   수업에서 사용했던 방향 값(예: -1, 0, 1)처럼 양방향 입력이 필요한 경우에는 2D Freeform Directional을 선택해야 했다 

 

* AudioSound

   동시에 여러 개의 사운드를 재생할 수 없기 때문에, 효과음을 겹쳐 재생하려면 각각 AudioSound가 필요하다

   ㄴ 소리를 중첩시킬 때, 애니메이션의 이벤트와 연결하여 트리거로 활용하기도 한다

 

* Time.timeScale(영상 재생 시 배속 조절과 유사한 개념)

   유니티의 시간의 흐름 속도를 조절할 수 있는 속성이다

   기본 값은 1f이며, 이는 정상적인 시간 흐름이다

   값을 0f으로 설정하면 시간이 완전히 정지되며, 애니메이션, 이동, 물리 처리 등 모두 멈춘다