언리얼 델리게이트로 트리거-반응 결합도 낮추기, 그리고 토글 상태의 베이스라인 패턴
터널 진입 시 자율주행 차량의 속도와 전방 주시 거리를 줄이는 기능을 구현하면서 정리한 두 가지 설계 패턴이다.
하나는 트리거와 반응을 델리게이트로 분리하는 것, 다른 하나는 토글 상태 값을 베이스라인 기준으로 관리하는 것이다.
트리거와 반응을 델리게이트로 분리
터널 트리거 액터와, 그에 반응해 속도를 바꾸는 자율주행 컴포넌트를 직접 연결하면 결합도가 높아진다.
차량 폰에 멀티캐스트 델리게이트를 두고, 트리거는 상태만 알리고, 반응이 필요한 컴포넌트가 구독하는 구조로 짰다.
DECLARE_MULTICAST_DELEGATE_OneParam(FOnTunnelStateChanged, bool);
FOnTunnelStateChanged OnTunnelToggleDelegate;
트리거 액터는 박스 오버랩만 감지해서 차량 폰의 상태 설정 함수를 호출하고, 그 함수가 델리게이트를 Broadcast한다.
구독은 반응하는 쪽에서 BeginPlay에 한 줄 추가하면 된다.
OwnerPawn->OnTunnelToggleDelegate.AddUObject(
this, &USplineFollowerComponent::OnTunnelToggled);
이 구조의 이점은 차량 폰이 어떤 컴포넌트가 구독하는지 알 필요가 없다는 것이다.
나중에 터널에 반응하는 다른 컴포넌트(예: 사운드, 라이트)를 추가해도 차량 폰 코드는 건드리지 않는다.
트리거-반응을 직접 참조로 묶지 않고 알림 채널로 분리하면, 반응 측을 자유롭게 늘릴 수 있다.
오버랩 트리거 자체는 AActor의 NotifyActorBeginOverlap / NotifyActorEndOverlap 가상 함수로 구현했다.
블루프린트의 OnActorBeginOverlap 이벤트와 같은 역할이다.
한 가지 주의할 점은, PIE 시작 시 차량이 이미 트리거 박스 안에 있으면 오버랩 이벤트가 늦게 발생하거나 누락될 수 있다는 것이다.
BeginPlay에서 GetOverlappingActors로 한 번 직접 확인해두면 이 경우가 메워진다.
토글 상태는 베이스라인 기준으로
터널 진입 시 속도를 70%로 줄이는 걸 단순하게 짜면 이렇게 된다.
if (bInTunnel)
MaxSpeed = MaxSpeed * 0.7f;
else
MaxSpeed = MaxSpeed / 0.7f;
이 방식은 곱하고 나누는 과정에서 부동소수점 오차가 누적된다.
터널을 여러 번 들락날락하면 원래 값에서 점점 멀어진다.
원본 값을 한 번만 저장해두고, 이후에는 항상 그 원본에 비율을 곱하는 방식으로 바꿨다.
if (!bBaselineCached)
{
BaselineMaxSpeed = MaxSpeed;
BaselineLookAheadBase = LookAheadBase;
bBaselineCached = true;
}
if (bInTunnel)
{
MaxSpeed = BaselineMaxSpeed * TunnelSpeedScale;
LookAheadBase = BaselineLookAheadBase * TunnelLookAheadScale;
SmoothedTargetSpeed = FMath::Min(SmoothedTargetSpeed, MaxSpeed);
}
else
{
MaxSpeed = BaselineMaxSpeed;
LookAheadBase = BaselineLookAheadBase;
}
이렇게 하면 몇 번을 토글해도 값이 정확하다.
가역적으로 보이는 곱하기·나누기보다, 원본을 보관하고 매번 원본에서 다시 계산하는 편이 누적 오차에 안전하다는 게 이 프로젝트에서 정리한 기준이다.
상태만 바꾸면 즉시 반영이 안 되는 경우
MaxSpeed만 줄여도 즉각적인 감속이 안 됐다.
자율주행 코드가 실제 사용하는 값(SmoothedTargetSpeed)을 천천히 보간하기 때문이다.
그래서 진입 시 현재 보간 값을 새 상한으로 한 번 클램프했다.
SmoothedTargetSpeed = FMath::Min(SmoothedTargetSpeed, MaxSpeed);
상한 값을 바꾸는 것과, 보간 중인 현재 값을 바꾸는 것은 별개라는 점이 핵심이다.
한도를 낮춰도 현재 값이 그 한도 위에 있으면 보간이 끝날 때까지는 효과가 늦으므로, 즉시 반영이 필요하면 현재 값 자체를 클램프해야 한다.
'etc' 카테고리의 다른 글
| 트리거 - 반응 동기화: 이벤트 방송 vs 매 프레임 폴링, 언제 무엇을 쓰는가 (0) | 2026.05.26 |
|---|---|
| 언리얼 Chaos Vehicle이 멈추지 않고 후진할 때: bReverseAsBrake와 상태 머신 이해 (0) | 2026.05.16 |
| 언리얼 런타임 SplineMeshComponent 동적 생성: 호출 순서·탄젠트 정규화·핫리로드 함정 (0) | 2026.05.16 |
| 언리얼 스플라인 경로 추종 차량이 도로 밖으로 튕길 때, 평면 조향과 이탈 페일세이프 분리 (0) | 2026.05.16 |
| 언리얼 자율주행 차량, 곡률 반경으로 안전 속도 계산하기 (V = √(μgR)) (0) | 2026.05.13 |
