Unreal) HitEvent, OnComponentHit
언리얼 엔진에서, 발사체가 적에게 명중했을 때 어떤 일이 발생해야 하는지, 혹은 캐릭터가 특정 오브젝트와 충돌했을 때 반응해야 하는 시나리오가 많다.
이런 상호작용의 핵심에는 바로 Hit Event와 델리게이트가 있다.
오늘은 이 두 가지 개념이 어떻게 유기적으로 작동하는지 살펴본다.
HitEvent
발사체 클래스 AProjectile
에는 OnHit
이라는 함수가 정의되어 있다.
이 친구가 바로 발사체가 무언가에 “부딪혔을 때” 호출되는 함수다.
void AProjectile::OnHit(UPRIMITIVECOMPONENT* HitComp, AActor* OtherActor, UPRIMITIVECOMPONENT* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
UE_LOG(LogTemp, Warning, TEXT("Projectile Hit"));
UE_LOG(LogTemp, Warning, TEXT("HitComp: %s"), *HitComp->GetName());
UE_LOG(LogTemp, Warning, TEXT("OtherActor: %s"), *OtherActor->GetName());
UE_LOG(LogTemp, Warning, TEXT("OtherComp: %s"), *OtherComp->GetName());
}
이 OnHit
함수는 다음과 같은 정보를 제공한다
HitComp
: 충돌을 일으킨 발사체 자신의 컴포넌트 (예: 구형 충돌체)OtherActor
: 충돌한 상대방 액터OtherComp
: 충돌한 상대방의 컴포넌트NormalImpulse
: 충돌 시 가해진 충격량Hit
: 충돌 지점, 노멀 등 상세 정보를 담은 구조체
보다시피, UE_LOG
를 통해 어떤 컴포넌트가, 어떤 액터와 충돌했는지 로그로 출력하는 것을 볼 수 있다.
OnComponentHit 델리게이트
OnHit
함수는 누가, 언제 호출해주나?
바로 델리게이트(Delegate)가 그 역할을 한다.
언리얼 엔진의 델리게이트는 특정 이벤트가 발생했을 때 호출될 함수들을 미리 등록해두고, 이벤트가 터지면 등록된 모든 함수를 한 번에 호출해주는 메커니즘이다.
OnComponentHit
는 UPrimitiveComponent
(충돌 감지를 담당하는 컴포넌트)에 내장된 특별한 델리게이트다.
이 델리게이트는 해당 컴포넌트가 다른 물리 오브젝트와 ‘Hit’ 이벤트를 감지하면 “충돌!”을 외치면서 자신에게 등록된 함수들을 모조리 호출한다.
우리 코드에서는 ProjectileMesh->OnComponentHit
으로 이 델리게이트에 접근한다.
ProjectileMesh
는 발사체의 충돌 감지 역할을 하는 UPrimitiveComponent
타입의 멤버 변수이다.
Hit Event + Delegate
이 모든 연결은 AProjectile
클래스의 BeginPlay()
함수에서 이루어진다.
void AProjectile::BeginPlay()
{
Super::BeginPlay();
// ProjectileMesh의 OnComponentHit 델리게이트에 AProjectile::OnHit 함수를 등록한다.
ProjectileMesh->OnComponentHit.AddDynamic(this, &AProjectile::OnHit);
}
여기서 ProjectileMesh->OnComponentHit.AddDynamic(this, &AProjectile::OnHit);
이 한 줄이 모든 작동의 명령이다.
ProjectileMesh->OnComponentHit
: 발사체의 메시 컴포넌트에 붙어있는OnComponentHit
델리게이트에 접근한다..AddDynamic(this, &AProjectile::OnHit)
: 이 델리게이트에 우리가 정의한AProjectile::OnHit
함수를 “구독”시킨다.this
: 현재AProjectile
인스턴스에서OnHit
함수를 찾아 호출하라는 의미다.&AProjectile::OnHit
:AProjectile
클래스의OnHit
함수의 주소(포인터)를 넘겨준다.
UE vs Unity
언리얼의 작동 방식
- 게임 시작 또는 발사체 스폰 시
BeginPlay()
에서OnHit
함수가ProjectileMesh
의OnComponentHit
델리게이트에 “구독”된다. - 이후
ProjectileMesh
가 다른 오브젝트와 충돌을 감지하면,OnComponentHit
델리게이트가 발동한다. - 델리게이트는 자신에게 등록된
OnHit
함수를 호출하며, 충돌 정보가 인자로 전달된다. OnHit
함수 내부의 로직(예: 로그 출력, 데미지 적용 등)이 실행된다.
장점
- 유연성: 하나의 델리게이트에 여러 함수를 등록할 수 있다 (멀티캐스트 델리게이트).
- 모듈화: 충돌 처리 로직을 별도의 함수로 분리하고, 필요한 시점에 동적으로 연결하거나 해제할 수 있다.
- 성능: 필요한 시점에만 함수가 호출되므로 효율적이다.
유니티의 작동 방식
Projectile
스크립트가 부착된 게임 오브젝트에Rigidbody
와Collider
컴포넌트가 있다고 가정한다.- 이 게임 오브젝트가 다른
Collider
가 있는 오브젝트와 충돌하면, 유니티 엔진은Projectile
스크립트를 찾아OnCollisionEnter
라는 이름의 함수가 있는지 확인한다. - 함수가 존재하면, 유니티는 자동으로
OnCollisionEnter
함수를 호출하고, 충돌에 대한 상세 정보(Collision
객체)를 인자로 전달한다. OnCollisionEnter
함수 내부의 로직(예: 로그 출력, 데미지 적용, 오브젝트 파괴 등)이 실행된다.
장점
- 단순성/직관성: 미리 정해진 이름의 함수를 정의하기만 하면 엔진이 자동으로 찾아 호출해준다.
- 빠른 프로토타이핑: 별도의 연결 과정 없이 함수만 추가하면 바로 작동한다.
using UnityEngine;
public class Projectile : MonoBehaviour
{
void OnCollisionEnter(Collision collision)
{
Debug.Log("Projectile Hit!");
Debug.Log("Collided with: " + collision.gameObject.name);
// 충돌한 오브젝트 정보 사용: collision.gameObject, collision.collider 등
}
}
정리
두 엔진 모두 충돌 처리를 위한 효과적인 방법을 제공하지만, 접근 방식에서 차이가 있다.
특징 | 언리얼 엔진 (델리게이트) | 유니티 (콜백 함수) |
---|---|---|
연결 방식 | 명시적 연결: AddDynamic 등으로 델리게이트에 함수를 등록해야 한다. |
암시적 연결: 특정 이름의 함수를 정의하면 엔진이 자동으로 찾아 호출한다. |
유연성 | 하나의 델리게이트에 여러 함수 등록 가능 (멀티캐스트), 동적 연결/해제. | 하나의 이벤트에 하나의 콜백 함수 (하지만 다른 스크립트에서도 동일 이벤트 처리 가능). |
제어 | 델리게이트를 직접 제어(Add, Remove, Broadcast 등)하여 이벤트 발생 시점을 정교하게 다룰 수 있다. | 엔진이 정해진 시점에 콜백 함수를 호출하며, 개발자가 호출 시점을 직접 제어하기 어렵다. |
성능 | 필요한 시점에만 함수가 호출되므로, 불필요한 함수 호출 오버헤드를 줄일 수 있다. | 엔진이 모든 콜백 함수를 탐색하므로, 상대적으로 약간의 오버헤드가 발생할 수 있다 (보통 무시할 수준). |
학습 곡선 | 델리게이트 개념을 익히는 데 약간의 시간이 필요할 수 있다. | 직관적이어서 초보자가 빠르게 이해하고 적용하기 쉽다. |
마무리
언리얼 엔진에서는 델리게이트를 사용하여 유연하고 강력한 이벤트 기반 프로그래밍을 할 수 있다.
Hit Event가 발생하면 OnComponentHit
델리게이트를 통해 미리 등록된 OnHit
함수를 호출함으로써, 발사체의 충돌 처리 로직을 깔끔하고 모듈화된 방식으로 구현하는 방법을 알아봤다.
언리얼의 델리게이트 방식은 강력한 유연성과 세밀한 제어가 강점이다.
특히 복잡한 시스템이나 대규모 프로젝트에서 이벤트 흐름을 명확하게 관리하는 데 유리하다.
반면 유니티의 콜백 함수 방식은 간단하고 직관적이어서 빠르게 기능을 구현하고 프로토타이핑하는 데 매우 효율적이다.
어떤 방식이 더 우월하다고 단정하기보다는, 각 엔진의 철학과 프로젝트의 규모 및 복잡성에 따라 적절한 장점을 활용하는 것이 현명하다.
결국 두 방식 모두 게임 개발자가 충돌 이벤트를 효과적으로 처리하고 원하는 게임 플레이를 구현할 수 있도록 돕는 훌륭한 도구임에는 변함이 없다.
댓글남기기