DecoratorNode 기반 클래스의 인터페이스 (Interface of the DecoratorNode Base Class)

DecoratorNode 기반 클래스의 인터페이스 (Interface of the DecoratorNode Base Class)

1. 개요

BT::DecoratorNode는 BehaviorTree.CPP에서 모든 데코레이터 노드의 기반이 되는 추상 클래스이다. 이 클래스는 단일 자식 관리, halt 전파, 기본 tick 프레임워크 등의 공통 기능을 제공하며, 사용자 정의 데코레이터는 이 클래스를 상속하여 tick() 메서드를 구현한다.

2. 클래스 선언

namespace BT
{
class DecoratorNode : public TreeNode
{
public:
    DecoratorNode(const std::string& name,
                  const NodeConfiguration& config);

    virtual ~DecoratorNode() override = default;

    // 자식 노드 설정 (팩토리에 의해 호출)
    void setChild(TreeNode* child);

    // 자식 접근자
    const TreeNode* child() const;
    TreeNode* child();

    // halt: 자식 halt 후 자신을 IDLE로 전환
    virtual void halt() override;

    // 노드 유형 반환
    NodeType type() const override
    {
        return NodeType::DECORATOR;
    }

protected:
    // 자식이 RUNNING이면 halt 호출
    void haltChild();

    TreeNode* child_node_;
};
}

3. 주요 메서드 상세

3.1 setChild()

void setChild(TreeNode* child);

데코레이터의 자식 노드를 설정한다. BehaviorTreeFactory가 XML을 파싱할 때 자동으로 호출되며, 사용자가 직접 호출하는 경우는 드물다.

3.2 child()

TreeNode* child();
const TreeNode* child() const;

자식 노드에 대한 포인터를 반환한다. tick() 메서드 내부에서 child_node_를 직접 접근하는 것이 일반적이나, 이 접근자를 통해서도 가능하다.

3.3 halt()

virtual void halt() override;

기본 구현:

  1. haltChild() 호출하여 자식의 실행을 중단
  2. 자신의 상태를 IDLE로 설정

사용자 정의 데코레이터에서 오버라이드할 때는, 자신의 내부 상태를 초기화한 후 기반 클래스의 halt()를 호출한다.

void MyDecorator::halt() override
{
    my_counter_ = 0;           // 내부 상태 초기화
    DecoratorNode::halt();      // 기반 클래스 호출
}

3.4 haltChild()

void haltChild();

자식이 RUNNING 상태인 경우에만 자식의 halt() 메서드를 호출하고, 자식의 상태를 IDLE로 설정한다. 자식이 이미 SUCCESS, FAILURE, 또는 IDLE 상태이면 아무 동작도 수행하지 않는다.

4. tick()의 구현 규약

4.1 필수 호출: executeTick()

자식을 tick할 때는 반드시 child_node_->executeTick()을 사용한다.

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

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

executeTick()tick()을 호출하기 전에 노드의 상태 전이 로직(IDLE→RUNNING 등)을 처리한다.

4.2 setStatus() 호출

tick() 메서드 시작 시 setStatus(NodeStatus::RUNNING)을 호출하여 데코레이터의 상태를 RUNNING으로 설정한다.

BT::NodeStatus tick() override
{
    setStatus(BT::NodeStatus::RUNNING);
    // ...
}

5. providedPorts()의 정의

입력/출력 포트가 필요한 데코레이터는 정적 providedPorts() 메서드를 정의한다.

static BT::PortsList providedPorts()
{
    return {
        BT::InputPort<int>("max_count", 5, "최대 횟수"),
        BT::InputPort<double>("timeout_sec", 10.0, "타임아웃")
    };
}

6. 설계 시 고려 사항

6.1 단일 자식 보장

DecoratorNode는 단일 child_node_ 포인터만 유지하므로, 복수의 자식을 설정하면 이전 자식이 대체된다. XML 파서가 이를 강제하므로, 런타임에서는 이 문제가 발생하지 않는다.

6.2 가상 소멸자

DecoratorNode는 가상 소멸자를 가지므로, 파생 클래스에서 동적 할당된 리소스를 안전하게 해제할 수 있다.

7. 참고 문헌

  • BehaviorTree.CPP 공식 문서. https://www.behaviortree.dev/
  • BehaviorTree.CPP 소스 코드. https://github.com/BehaviorTree/BehaviorTree.CPP

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