커스텀 데코레이터의 tick() 구현 (Custom Decorator's tick() Implementation)

커스텀 데코레이터의 tick() 구현 (Custom Decorator’s tick() Implementation)

1. 개요

커스텀 데코레이터의 tick() 메서드는 데코레이터의 핵심 동작 로직을 구현하는 곳이다. 자식 노드의 tick 호출, 반환 상태의 변환, 내부 상태 갱신, 전처리/후처리 로직 등이 이 메서드에서 수행된다.

2. tick() 구현의 기본 구조

BT::NodeStatus tick() override
{
    // 1. 상태를 RUNNING으로 설정
    setStatus(BT::NodeStatus::RUNNING);

    // 2. 전처리 로직 (선택)
    if (shouldSkipChild())
    {
        return BT::NodeStatus::FAILURE;
    }

    // 3. 자식 tick
    BT::NodeStatus child_status = child_node_->executeTick();

    // 4. 후처리 로직 (선택)
    return processResult(child_status);
}

3. 자식 tick 호출 규약

3.1 executeTick() 사용 필수

// 올바름: executeTick()
auto status = child_node_->executeTick();

// 부적절: tick() 직접 호출 (상태 관리 누락)
auto status = child_node_->tick();

executeTick()tick() 호출 전에 노드의 상태 전이 로직을 수행하므로, 반드시 executeTick()을 사용한다.

4. 상태 변환 데코레이터의 tick() 예시

// Inverter의 tick()
BT::NodeStatus tick() override
{
    setStatus(BT::NodeStatus::RUNNING);
    auto status = child_node_->executeTick();

    switch (status)
    {
    case BT::NodeStatus::SUCCESS: return BT::NodeStatus::FAILURE;
    case BT::NodeStatus::FAILURE: return BT::NodeStatus::SUCCESS;
    case BT::NodeStatus::RUNNING: return BT::NodeStatus::RUNNING;
    default: throw BT::LogicError("Invalid status");
    }
}

5. 상태 유지 데코레이터의 tick() 예시

// CooldownDecorator의 tick()
BT::NodeStatus tick() override
{
    setStatus(BT::NodeStatus::RUNNING);

    double cooldown_sec;
    getInput("cooldown_sec", cooldown_sec);

    auto now = std::chrono::steady_clock::now();
    auto elapsed = std::chrono::duration<double>(
        now - last_success_time_).count();

    // 전처리: 쿨다운 미경과 시 자식 skip
    if (elapsed < cooldown_sec)
    {
        return BT::NodeStatus::FAILURE;
    }

    // 자식 tick
    auto child_status = child_node_->executeTick();

    // 후처리: 성공 시 타이머 갱신
    if (child_status == BT::NodeStatus::SUCCESS)
    {
        last_success_time_ = now;
    }

    return child_status;
}

6. tick() 구현 시 주의 사항

6.1 RUNNING 통과 보장

대부분의 데코레이터에서 자식의 RUNNING 상태를 변환하지 않고 그대로 반환하여야 한다.

6.2 setStatus() 호출

tick() 시작 시 setStatus(BT::NodeStatus::RUNNING)을 호출하여 데코레이터의 상태를 올바르게 설정한다.

6.3 자식 미실행 시 halt 호출

전처리에서 자식을 tick하지 않기로 결정한 경우, 자식이 이전 tick에서 RUNNING 상태였으면 haltChild()를 호출하여야 한다.

if (shouldSkipChild())
{
    haltChild();  // 이전에 RUNNING이었으면 halt
    return BT::NodeStatus::FAILURE;
}

7. 참고 문헌

  • BehaviorTree.CPP 공식 문서. https://www.behaviortree.dev/

버전날짜변경 사항
v0.12026-04-05초안 작성