트리거-반응 동기화: 이벤트 방송 vs 매 프레임 폴링, 언제 무엇을 쓰는가

게임이나 시뮬레이션을 만들다 보면 "어떤 상황이 발생했을 때 다른 컴포넌트가 반응하게 하는" 코드를 자주 짠다. 캐릭터가 위험 구역에 들어가면 UI에 경고를 띄우고, 차량이 장애물 앞에 오면 속도를 줄이고, 아이템을 획득하면 인벤토리가 갱신되는 식이다.

이런 트리거-반응 동기화에 흔히 쓰는 두 가지 패턴이 있다.

A. 진입/해제 이벤트 방송 — 상태가 바뀐 순간에만 방송, 반응 쪽은 구독
B. 매 프레임 현재 상황 폴링 — 반응 쪽이 매 프레임 "지금 상황이 뭔지" 물어봄

 

두 패턴은 자주 같은 자리에 놓고 비교되지만 적절한 선택은 상황마다 다르다. 이 글에서는 자율주행 시뮬레이터 프로젝트에서 같은 종류의 트리거-반응을 두 가지 방식으로 의도적으로 다르게 설계한 사례를 통해, 언제 어느 쪽을 택해야 하는지의 판단 기준을 정리한다.

이벤트 방송 (위험 감지 시스템)

차량 거동에서 위험을 감지하는 시스템은 이벤트 방식으로 설계했다.

void UHazardDetectorComponent::CheckSlip()
{
    // ... 측정 ...

    // 진입 판정
    if (!bSlipActive && SlipAngleDeg >= SlipEnterDeg)
    {
        bSlipActive = true;
        BroadcastSlip(EHazardPhase::Enter, SlipAngleDeg, Car, Speed);
    }
    // 해제 판정
    else if (bSlipActive && SlipAngleDeg < SlipExitDeg)
    {
        bSlipActive = false;
        BroadcastSlip(EHazardPhase::Exit, SlipAngleDeg, Car, Speed);
    }
}

 

핵심은 "진입한 순간"과 "해제된 순간"을 각각 별도 이벤트로 방송한다는 점이다. 구독자(데이터 로거)는 이 두 사건을 받아 시계열 데이터로 기록한다.

12.34초  Skid Enter  위치 X  슬립각 18도
12.89초  Skid Exit   위치 Y  슬립각  9도

매 프레임 폴링 (전방 감지 시스템)

차량이 전방 과속방지턱을 감지하고 속도를 줄이는 시스템은 폴링 방식으로 설계했다.

// SplineFollower의 UpdateTargetSpeed 안에서 매 프레임 호출
const float BumpSpeed = CheckSpeedBumpAhead(VehicleSpeedNow);
if (BumpSpeed > 0.f)
{
    SpeedLimit = FMath::Min(SpeedLimit, BumpSpeed);
}

 

CheckSpeedBumpAhead는 매 프레임 "지금 전방에 과속방지턱이 있나"를 묻고, 있으면 줄여야 할 속도를, 없으면 -1을 반환한다. 진입을 따로 알릴 필요도 없고, 통과 후 복원을 위한 별도 로직도 없다. 통과하면 자연스럽게 검사 함수가 -1을 반환하고 SpeedLimit이 다른 제한들로 다시 결정된다.

왜 둘을 다르게 설계했나

같은 종류의 트리거-반응처럼 보이지만 설계 결정이 정반대로 갈린 이유는 명확하다.

위험 감지: "사건"이 분석 단위 → 시작과 끝을 각각 기록할 필요 있음
전방 감지: "현재 상황"이 결정 단위 → 상태를 기억할 필요 없음

 

위험 감지의 결과물은 데이터 분석에 쓰일 시계열 로그다. "12.34초에 슬립이 시작됐고 12.89초에 끝났다"라는 사건의 시작과 끝이 분석의 단위가 된다. 만약 매 프레임 "지금 슬립 중인가?"만 폴링했다면, 매 프레임 같은 상태가 60번씩 찍혀 분석이 불가능해진다.

전방 감지의 결과물은 차량의 현재 속도 결정이다. "지금 이 순간 전방에 무엇이 있는가"만 알면 충분하고, 언제 진입했는지나 얼마나 오래 있었는지는 결정에 영향을 주지 않는다. 매 프레임 같은 질문을 던지면 된다.

이벤트 방식의 장점과 함정

장점은 명확하다.

  • 발생 빈도가 낮은 사건에서 효율적이다. 폴링은 일어나지 않는 상황도 매 프레임 확인하지만, 이벤트는 변화가 있을 때만 동작한다
  • 구독자가 사건의 시작과 끝을 정확히 알 수 있다. 시계열 분석, 통계 집계, 로그 기록에 적합하다
  • 발신자와 수신자가 결합하지 않는다. 델리게이트만 알면 누가 구독하든 발신자는 모른다

함정은 상태가 어긋날 수 있다는 점이다.

  • 진입 이벤트는 방송했는데 해제 이벤트가 누락되면 수신자는 영영 "진입 상태"로 남는다
  • 게임 중간에 합류한 컴포넌트는 "이미 진입 중인 상태"를 모른다. 별도 초기 동기화 로직이 필요하다
  • 이벤트 순서가 꼬이면 (해제 → 진입처럼 거꾸로 도착하면) 상태가 잘못된다

이 함정들은 "사건"이 분석의 단위인 경우에는 감수할 만하다. 분석 데이터에서는 누락된 사건을 후처리로 찾을 수 있다. 하지만 "현재 결정"이 목적이라면 이 함정 하나가 곧장 차가 영영 감속 상태에 머무는 사고로 이어진다.

폴링 방식의 장점과 함정

장점은 단순함이다.

  • 상태가 어긋날 수 없다. 매 프레임 새로 판단하기 때문에 이전 프레임의 잘못된 상태가 남지 않는다
  • 진입과 해제를 따로 짤 필요가 없다. 통과는 단지 "더 이상 조건이 안 맞음"의 자연스러운 결과다
  • 중간 합류 문제가 없다. 새로 들어온 컴포넌트도 다음 프레임에 정상 동작한다

함정은 비용이다.

  • 발생 빈도가 낮은 사건도 매 프레임 확인한다. 검사 비용이 클수록 부담이 커진다
  • 사건의 정확한 시작과 끝 시각을 모른다. "프레임 N에는 있었고 프레임 N+1에는 없었다"만 알 수 있다
  • 두 프레임 사이에 일어난 짧은 사건은 놓칠 수 있다

이 함정들은 "현재 결정"이 목적인 경우에는 거의 문제가 되지 않는다. 매 프레임 결정하니까 시작 시각을 굳이 알 필요가 없고, 짧은 사건은 어차피 결정에 영향이 없다.

판단 기준

두 패턴 중 무엇을 쓸지의 판단은 "결과물이 무엇을 위한 것인가"에서 갈린다.

결과물이 분석할 데이터(시계열 로그, 사건 통계)        → 이벤트 방송
결과물이 매 프레임 결정(속도, 위치, 상태 분기)         → 매 프레임 폴링

 

같은 자율주행 시뮬레이터에서 위험 감지가 이벤트, 전방 감지가 폴링으로 갈린 것이 이 기준의 직접적인 적용 사례다. 분석을 위해서는 사건의 경계가 필요하고, 결정을 위해서는 현재 상황만 필요하다.

이 기준을 의식하지 못하면 두 가지 흔한 실수가 발생한다.

 

첫째, 매 프레임 결정해야 하는 자리에 이벤트 방식을 쓰는 경우. "차량이 위험 구역에 진입했다"는 이벤트를 받고 속도 제한 상태를 켰는데, 해제 이벤트가 누락되거나 순서가 꼬여서 차가 영영 감속 상태에 머문다. 진입/해제 두 사건의 정합성을 맞추는 데 코드 절반을 쓰게 된다.

 

둘째, 분석 데이터가 필요한 자리에 폴링을 쓰는 경우. 매 프레임 "지금 슬립 중인가?"를 로그에 찍으면 60Hz × 슬립 지속 시간만큼 같은 데이터가 쌓여 분석이 불가능해진다. 사후에 "연속된 같은 상태를 묶기"라는 후처리를 짜야 한다.

각 패턴의 장점이 다른 자리에서는 함정으로 변한다. 어느 쪽이 좋고 나쁜 게 아니라, 결과물의 성격에 맞춰 선택하는 것이 핵심이다.

함께 쓰는 경우

한 시스템 안에서 두 패턴이 같이 등장하기도 한다. 위 사례의 위험 감지 컴포넌트도 내부 로직을 잘 보면 매 프레임 폴링으로 측정하고, 그 결과가 임계값을 넘는 순간에만 이벤트를 방송한다.

매 프레임 폴링 (CheckSlip)
  → 측정 (현재 슬립각 계산)
  → 임계값 비교
  → 상태가 바뀐 순간에만 이벤트 방송 (Enter / Exit)

 

이건 두 패턴 중 하나를 고른 것이 아니라, "내부는 폴링으로 측정하고 외부에는 이벤트로 통보한다"는 조합이다. 측정 자체는 매 프레임 일어나야 정확하지만 (놓치면 안 되니까) 외부에 알리는 것은 사건 단위로만 일어나야 한다 (분석에 쓰여야 하니까).

이 조합 패턴은 다른 영역에도 그대로 쓰인다. 입력 처리에서 키 상태는 매 프레임 폴링하지만 "키가 막 눌렸다"는 사건만 다른 시스템에 알리는 것, 충돌 검사에서 매 프레임 위치를 비교하지만 "막 충돌했다"는 순간만 이벤트로 방송하는 것이 같은 구조다.

내부 측정과 외부 통보의 단위를 분리하는 감각이 두 패턴 중 어느 한쪽에 매몰되지 않게 해준다.

+ Recent posts