본문 바로가기
공부/유니티

유니티 물리와 이벤트 함수 정리 - 힘, 충돌, 생명주기 함수

by Excidus 2023. 4. 9.

유니티(Unity)를 공부하며 물리 시스템과 이벤트 함수의 핵심 개념을 정리했다. 이번 학습은 물리 기반 힘 적용과 유니티의 이벤트 함수 동작 방식을 이해하는 데 초점을 맞췄으며, 실제 프로젝트에서 테스트하며 얻은 경험을 반영했다.

1. 물리 시스템: 연속적인 힘과 순간적인 힘

유니티의 물리 시스템에서 힘은 오브젝트의 움직임을 제어하는 핵심 요소다. 힘의 적용 방식은 연속적인 힘과 순간적인 힘으로 나뉜다.

연속적인 힘

  • 정의: 자동차 엑셀처럼 지속적으로 가속을 추가하는 방식이다. 이미 움직이는 오브젝트에 적합하다.
  • ForceMode:
    • ForceMode.Force: 오브젝트의 질량을 고려해 힘을 적용한다.
    • ForceMode.Acceleration: 질량을 무시하고 가속을 적용한다.
  • 구현 경험: 차량 이동 로직을 구현하며 ForceMode.Force를 사용해 무게감 있는 가속을 테스트했다. 초기에는 가속이 너무 급격해 부자연스러웠으나, 힘의 크기를 조정해 부드럽게 만들었다.
  • 배운 점: 연속적인 힘은 지속적인 움직임을 구현할 때 유용하며, 질량에 따라 동작이 달라진다는 점을 고려해야 한다.

순간적인 힘

  • 정의: 뒤에서 미는 것처럼 순간적으로 속도를 부여하는 방식이다. 정지 상태에서 움직임을 시작할 때 적합하다.
  • ForceMode:
    • ForceMode.Impulse: 질량을 고려해 순간적인 힘을 적용한다.
    • ForceMode.VelocityChange: 질량을 무시하고 속도를 즉시 변경한다.
  • 구현 경험: 캐릭터 점프를 구현하며 ForceMode.Impulse를 사용했다. 점프 높이가 일정하지 않은 문제를 발견하고, Rigidbody의 질량과 힘의 크기를 조정해 해결했다.
  • 배운 점: 순간적인 힘은 빠른 반응이 필요한 상황에서 효과적이며, ImpulseVelocityChange의 차이를 이해하는 것이 중요하다.

물리 설정

  • Project Settings > Physics: 중력, 마찰 등 물리 값을 조정할 수 있다. 예를 들어, 중력을 낮춰 점프의 느낌을 조정하며 테스트했다.
  • 배운 점: 물리 설정은 게임의 전반적인 느낌에 큰 영향을 미친다. 디테일한 조정이 필수적이다.

2. 이벤트 함수

이벤트 함수는 별도의 호출 없이 자동으로 실행되며, 호출 시점이 정해져 있다. 유니티의 생명주기와 상호작용을 관리하는 데 핵심적인 역할을 한다.

Reset()

  • 정의: 스크립트가 에디터에서 처음 연결되거나 Reset 명령 실행 시 호출된다.
  • 구현 경험: 컴포넌트 초기 설정을 위해 Reset()을 사용했으나, 예상치 못한 호출로 변수가 초기화되는 문제를 겪었다. 호출 시점을 명확히 파악해 해결했다.
  • 배운 점: Reset()은 에디터 작업에 유용하지만, 런타임에는 영향을 미치지 않으므로 주의해야 한다.

Awake(), OnEnable(), Start()

  • 정의:
    • Awake(): 오브젝트 생성 직후, 모든 스크립트 로드 시 호출된다. 초기화 작업에 사용된다.
    • OnEnable(): 오브젝트 또는 스크립트 활성화 시 호출되며, Awake() 이후, Start() 이전에 실행된다.
    • Start(): 첫 프레임의 Update() 직전에 호출되며, 다른 스크립트 초기화에 의존하는 작업에 적합하다.
    • 순서: Awake() -> OnEnable() -> Start()
  • 구현 경험: Awake()에서 참조를 설정하고, Start()에서 참조를 활용하는 패턴을 적용했다. 초기에는 OnEnable()의 호출 시점을 몰라 혼란스러웠으나, 문서를 참고해 명확히 이해했다.
  • 배운 점: 초기화 순서를 정확히 파악하면 안정적인 스크립트 설계가 가능하다.

OnDisable()

  • 정의: 오브젝트 또는 스크립트 비활성화 시 호출된다.
  • 구현 경험: 오브젝트 풀링을 구현하며 OnDisable()에서 리소스 정리를 처리했다. 비활성화 시점이 명확해 코드가 간결해졌다.
  • 배운 점: OnDisable()은 리소스 관리와 상태 초기화에 유용하다.

OnCollisionXXX vs OnTriggerXXX

  • 정의:
    • OnCollisionXXX: 물리적 충돌(충격, 마찰 등)을 처리하며, OnCollisionEnter, OnCollisionStay, OnCollisionExit 등이 있다.
    • OnTriggerXXX: 물리 연산 없이 트리거 충돌을 감지하며, OnTriggerEnter, OnTriggerStay, OnTriggerExit 등이 있다.
  • 구현 경험: 적과의 충돌을 OnCollisionEnter로 처리하며 데미지를 적용했다. OnCollisionStay가 예상보다 호출되지 않는 문제를 발견하고, Rigidbody의 Sleeping Mode를 Never Sleep으로 변경해 해결했다.
  • 배운 점: Collision은 물리적 상호작용, Trigger는 논리적 이벤트 처리에 적합하다. Sleeping Mode 설정은 물리 안정성에 영향을 미친다.

OnMouseXXX

  • 정의: Collider가 있는 오브젝트에서 마우스 입력(또는 터치)을 감지한다.
    • OnMouseDown: 클릭 시 호출.
    • OnMouseUp: 클릭 해제 시 호출.
    • OnMouseDrag: 클릭 중 드래그 시 호출.
  • 구현 경험: UI 버튼 대신 3D 오브젝트 클릭을 구현하며 OnMouseDown을 사용했다. 터치 입력이 제대로 감지되지 않는 문제를 해결하기 위해 Collider 크기를 조정했다.
  • 배운 점: OnMouseXXX는 간단한 상호작용 구현에 유용하지만, 모바일 환경에서는 터치 처리에 주의해야 한다.

FixedUpdate()

  • 정의: 고정된 시간 간격(기본 0.02초)으로 호출되며, 물리 연산에 적합하다. Edit > Project Settings > Time > Fixed Timestep에서 간격을 조정할 수 있다.
  • 구현 경험: 캐릭터 이동을 Update()로 처리했으나, 프레임 드롭으로 불균일한 움직임이 발생했다. FixedUpdate()로 전환해 안정적인 물리 처리를 구현했다.
  • 배운 점: FixedUpdate()는 기기 성능에 관계없이 일정한 물리 계산을 보장한다.

LateUpdate()

  • 정의: Update() 이후 호출되며, 카메라 이동 등 후처리 작업에 사용된다.
  • 구현 경험: 카메라가 캐릭터를 따라가도록 LateUpdate()에서 위치를 조정했다. Update()에서 처리했을 때 카메라가 끊기는 문제를 해결했다.
  • 배운 점: LateUpdate()는 오브젝트 이동 후 보정 작업에 최적이다.

OnBecameVisible() / OnBecameInvisible()

  • 정의: 오브젝트가 카메라에 보이거나 사라질 때 호출된다.
  • 구현 경험: UI 요소의 렌더링 최적화를 위해 OnBecameInvisible()에서 리소스를 비활성화했다. Scene 뷰로 인해 OnBecameVisible()이 예기치 않게 호출되는 문제를 Scene 뷰 비활성화로 해결했다.
  • 배운 점: Scene 뷰와 Game 뷰의 상호작용을 고려해야 정확한 테스트가 가능하다.

3. 개발 중 주요 이슈와 해결

  • Sleeping Mode 문제: OnCollisionStay가 중단되는 문제를 Rigidbody의 Sleeping Mode 설정으로 해결했다. 물리 설정의 디테일한 조정이 중요함을 깨달았다.
  • 이벤트 함수 혼란: Awake(), OnEnable(), Start()의 호출 순서를 혼동해 초기화 오류가 발생했다. 공식 문서와 테스트로 순서를 명확히 정리했다.
  • 카메라 이동 끊김: Update()에서 카메라 이동을 처리했을 때 부자연스러운 움직임을 LateUpdate()로 전환해 해결했다.

4. 마무리

이번 학습을 통해 유니티의 물리 시스템과 이벤트 함수의 동작 방식을 깊이 이해할 수 있었다. 특히 힘의 적용 방식과 이벤트 함수의 호출 시점이 게임 로직 설계에 큰 영향을 미친다는 점을 체감했다.