行为树例子2

<root BTCPP_format="4">
    <BehaviorTree ID="MainTree">
        <Sequence name="GoHomeAndDine">
            <!-- 准备饭菜 -->
            <Sequence name="PrepareMeal">
                <Action ID="WashVegetables" name="wash_vegetables"/>
                <Action ID="PrepareDishes" name="prepare_dishes"/>
            </Sequence>
            <!-- 同时做菜和煮饭 -->
            <Parallel policy="require_one_success" name="CookInParallel">
                <Action ID="CookDishes" name="cook_dishes"/>
                <Action ID="CookRice" name="cook_rice"/>
            </Parallel>
            <!-- 吃饭 -->
            <Action ID="Eat" name="eat"/>
            <!-- 洗碗 -->
            <Action ID="WashDishes" name="wash_dishes"/>
        </Sequence>
    </BehaviorTree>
</root>  

在这里插入图片描述
根据提供的XML行为树结构,以下是业务逻辑的描述和对应的C++代码实现。

业务逻辑描述:

  1. 洗菜(WashVegetables):准备食材。
  2. 准备菜(PrepareDishes):将食材加工成可烹饪状态。
  3. 同时做菜和煮饭(CookInParallel)
    • 做菜(CookDishes):烹饪食材成菜肴。
    • 煮饭(CookRice):准备米饭。
    • 只要做菜或煮饭中的一个完成,就可以继续下一步。
  4. 吃饭(Eat):享用烹饪好的食物和米饭。
  5. 洗碗(WashDishes):清洗使用过的餐具。

C++代码实现:

#include "behaviortree_cpp_v3/bt_factory.h"

// 洗菜动作节点
class WashVegetables : public BT::SyncActionNode {
public:
    WashVegetables(const std::string& name) : BT::SyncActionNode(name, {}) {}

    BT::NodeStatus tick() override {
        // 洗菜逻辑
        std::cout << "Washing vegetables." << std::endl;
        // 假设洗菜总是成功
        return BT::NodeStatus::SUCCESS;
    }
};

// 准备菜动作节点
class PrepareDishes : public BT::SyncActionNode {
public:
    PrepareDishes(const std::string& name) : BT::SyncActionNode(name, {}) {}

    BT::NodeStatus tick() override {
        // 准备菜逻辑
        std::cout << "Preparing dishes." << std::endl;
        // 假设准备菜总是成功
        return BT::NodeStatus::SUCCESS;
    }
};

// 做菜动作节点
class CookDishes : public BT::SyncActionNode {
public:
    CookDishes(const std::string& name) : BT::SyncActionNode(name, {}) {}

    BT::NodeStatus tick() override {
        // 做菜逻辑
        std::cout << "Cooking dishes." << std::endl;
        // 假设做菜可能需要一些时间
        return BT::NodeStatus::RUNNING; // 这里假设返回RUNNING表示需要更多时间
    }
};

// 煮饭动作节点
class CookRice : public BT::SyncActionNode {
public:
    CookRice(const std::string& name) : BT::SyncActionNode(name, {}) {}

    BT::NodeStatus tick() override {
        // 煮饭逻辑
        std::cout << "Cooking rice." << std::endl;
        // 假设煮饭可能需要一些时间
        return BT::NodeStatus::RUNNING; // 这里假设返回RUNNING表示需要更多时间
    }
};

// 吃饭动作节点
class Eat : public BT::SyncActionNode {
public:
    Eat(const std::string& name) : BT::SyncActionNode(name, {}) {}

    BT::NodeStatus tick() override {
        // 吃饭逻辑
        std::cout << "Eating." << std::endl;
        // 假设吃饭总是成功
        return BT::NodeStatus::SUCCESS;
    }
};

// 洗碗动作节点
class WashDishes : public BT::SyncActionNode {
public:
    WashDishes(const std::string& name) : BT::SyncActionNode(name, {}) {}

    BT::NodeStatus tick() override {
        // 洗碗逻辑
        std::cout << "Washing dishes." << std::endl;
        // 假设洗碗总是成功
        return BT::NodeStatus::SUCCESS;
    }
};

int main() {
    BT::BehaviorTreeFactory factory;

    // 注册自定义节点
    factory.registerNodeType<WashVegetables>("WashVegetables");
    factory.registerNodeType<PrepareDishes>("PrepareDishes");
    factory.registerNodeType<CookDishes>("CookDishes");
    factory.registerNodeType<CookRice>("CookRice");
    factory.registerNodeType<Eat>("Eat");
    factory.registerNodeType<WashDishes>("WashDishes");

    // 加载XML文件并创建行为树
    auto tree = factory.createTreeFromFile("behavior_tree.xml");

    // 运行行为树
    tree.tickWhileRunning();

    return 0;
}

请注意,上述代码中的CookDishesCookRice节点返回RUNNING状态,表示这些动作可能需要一定时间才能完成。在实际应用中,您可能需要添加一些逻辑来确定何时这些动作真正完成,并从RUNNING状态转换到SUCCESSFAILURE状态。

此外,tickWhileRunning函数会持续地触发行为树,直到行为树返回完成状态(SUCCESSFAILURE)。在本例中,只要CookDishesCookRice中的一个完成,行为树就会继续执行Eat节点,然后是WashDishes节点。

  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值