@@ -71,38 +71,44 @@ Next, create the tree:
7171```cpp
7272using namespace aitoolkit::bt;
7373
74- auto tree = sel<blackboard_type>::make({
75- seq<blackboard_type>::make({
76- check<blackboard_type>::make([](const blackboard_type& bb) {
77- auto distance = glm::distance(bb.agent_position, bb.enemy_position);
78- return distance <= bb.attack_range;
79- }),
80- task<blackboard_type>::make([](blackboard_type& bb) {
81- // Destroy enemy
82- return execution_state::success;
83- })
84- }),
85- seq<blackboard_type>::make({
86- check<blackboard_type>::make([](const blackboard_type& bb) {
87- auto distance = glm::distance(bb.agent_position, bb.enemy_position);
88- return distance <= bb.sight_range;
89- }),
90- task<blackboard_type>::make([](blackboard_type& bb) {
91- // Move towards enemy
92- return execution_state::success;
93- })
94- }),
95- seq<blackboard_type>::make({
96- task<blackboard_type>::make([](blackboard_type& bb) {
97- // Move towards waypoint
98- return execution_state::success;
99- }),
100- task<blackboard_type>::make([](blackboard_type& bb) {
101- // Select next waypoint
102- return execution_state::success;
74+ auto tree = sel<blackboard_type>(
75+ node_list<blackboard_type>(
76+ seq<blackboard_type>(
77+ node_list<blackboard_type>(
78+ check<blackboard_type>([](const blackboard_type& bb) {
79+ auto distance = glm::distance(bb.agent_position, bb.enemy_position);
80+ return distance <= bb.attack_range;
81+ }),
82+ task<blackboard_type>([](blackboard_type& bb) {
83+ // Destroy enemy
84+ return execution_state::success;
85+ })
86+ )
87+ ),
88+ seq<blackboard_type>(
89+ node_list<blackboard_type>(
90+ check<blackboard_type>([](const blackboard_type& bb) {
91+ auto distance = glm::distance(bb.agent_position, bb.enemy_position);
92+ return distance <= bb.sight_range;
93+ }),
94+ task<blackboard_type>([](blackboard_type& bb) {
95+ // Move towards enemy
96+ return execution_state::success;
97+ })
98+ )
99+ ),
100+ seq<blackboard_type>::make({
101+ task<blackboard_type>([](blackboard_type& bb) {
102+ // Move towards waypoint
103+ return execution_state::success;
104+ }),
105+ task<blackboard_type>([](blackboard_type& bb) {
106+ // Select next waypoint
107+ return execution_state::success;
108+ })
103109 })
104- } )
105- } );
110+ )
111+ );
106112```
107113
108114Finally, evaluate the tree:
@@ -116,19 +122,21 @@ auto bb = blackboard_type{
116122};
117123
118124while (true) {
119- auto state = tree-> evaluate(bb);
125+ auto state = tree. evaluate(bb);
120126 if (state == execution_state::success) {
121127 break;
122128 }
123129}
124130```
125131*/
126132
127- #include < initializer_list>
128133#include < functional>
129134#include < memory>
130135#include < vector>
131136
137+ #include < type_traits>
138+ #include < concepts>
139+
132140namespace aitoolkit ::bt {
133141 /* *
134142 * @ingroup behtree
@@ -149,18 +157,41 @@ namespace aitoolkit::bt {
149157 template <class T >
150158 class node {
151159 public:
160+ node () = default ;
161+ node (const node&) = delete ;
162+ node (node&& other) {
163+ m_children = std::move (other.m_children );
164+ }
165+
166+ virtual ~node () = default ;
167+
152168 virtual execution_state evaluate (T& blackboard) const = 0;
153169
154170 protected:
155- std::vector<std::shared_ptr <node<T>>> m_children;
171+ std::vector<std::unique_ptr <node<T>>> m_children;
156172 };
157173
158174 /* *
159175 * @ingroup behtree
160176 * @brief Heap-allocated pointer to node
161177 */
162178 template <class T >
163- using node_ptr = std::shared_ptr<node<T>>;
179+ using node_ptr = std::unique_ptr<node<T>>;
180+
181+ template <typename N, class T >
182+ concept node_trait = std::derived_from<N, node<T>>;
183+
184+ /* *
185+ * @ingroup behtree
186+ * @brief Helper function to create a list of nodes
187+ */
188+ template <typename T, node_trait<T> ...Children>
189+ std::vector<node_ptr<T>> node_list (Children&&... children) {
190+ auto nodes = std::vector<node_ptr<T>>{};
191+ nodes.reserve (sizeof ...(children));
192+ (nodes.push_back (std::make_unique<Children>(std::move (children))), ...);
193+ return nodes;
194+ }
164195
165196 /* *
166197 * @ingroup behtree
@@ -170,19 +201,12 @@ namespace aitoolkit::bt {
170201 template <class T >
171202 class seq final : public node<T> {
172203 public:
173- static node_ptr<T> make (std::initializer_list<node_ptr<T>> children) {
174- auto seq_node = std::make_shared<seq<T>>();
175- seq_node->m_children .reserve (children.size ());
176-
177- for (auto & child : children) {
178- seq_node->m_children .push_back (child);
179- }
180-
181- return seq_node;
204+ seq (std::vector<node_ptr<T>> children) {
205+ this ->m_children = std::move (children);
182206 }
183207
184208 virtual execution_state evaluate (T& blackboard) const override {
185- for (auto child : this ->m_children ) {
209+ for (auto & child : this ->m_children ) {
186210 auto state = child->evaluate (blackboard);
187211 if (state != execution_state::success) {
188212 return state;
@@ -201,19 +225,12 @@ namespace aitoolkit::bt {
201225 template <class T >
202226 class sel final : public node<T> {
203227 public:
204- static node_ptr<T> make (std::initializer_list<node_ptr<T>> children) {
205- auto sel_node = std::make_shared<sel<T>>();
206- sel_node->m_children .reserve (children.size ());
207-
208- for (auto child : children) {
209- sel_node->m_children .push_back (child);
210- }
211-
212- return sel_node;
228+ sel (std::vector<node_ptr<T>> children) {
229+ this ->m_children = std::move (children);
213230 }
214231
215232 virtual execution_state evaluate (T& blackboard) const override {
216- for (auto child : this ->m_children ) {
233+ for (auto & child : this ->m_children ) {
217234 auto state = child->evaluate (blackboard);
218235 if (state != execution_state::failure) {
219236 return state;
@@ -232,21 +249,19 @@ namespace aitoolkit::bt {
232249 template <class T >
233250 class neg final : public node<T> {
234251 public:
235- static node_ptr<T> make (node_ptr<T> child) {
236- auto neg_node = std::make_shared<neg<T>>();
237-
238- neg_node->m_children .reserve (1 );
239- neg_node->m_children .push_back (child);
240-
241- return neg_node;
252+ template <node_trait<T> N>
253+ neg (N&& child) {
254+ this ->m_children .reserve (1 );
255+ this ->m_children .push_back (std::make_unique<N>(std::move (child)));
242256 }
243257
244258 virtual execution_state evaluate (T& blackboard) const override {
245259 if (this ->m_children .size () != 1 ) {
246260 return execution_state::failure;
247261 }
248262
249- auto state = this ->m_children .front ()->evaluate (blackboard);
263+ auto & child = this ->m_children .front ();
264+ auto state = child->evaluate (blackboard);
250265 if (state == execution_state::success) {
251266 return execution_state::failure;
252267 } else if (state == execution_state::failure) {
@@ -268,10 +283,6 @@ namespace aitoolkit::bt {
268283 using callback_type = std::function<bool (const T&)>;
269284
270285 public:
271- static node_ptr<T> make (callback_type fn) {
272- return std::make_shared<check<T>>(fn);
273- }
274-
275286 check (callback_type fn) : m_fn(fn) {}
276287
277288 virtual execution_state evaluate (T& blackboard) const override {
@@ -297,10 +308,6 @@ namespace aitoolkit::bt {
297308 using callback_type = std::function<execution_state(T&)>;
298309
299310 public:
300- static node_ptr<T> make (callback_type fn) {
301- return std::make_shared<task<T>>(fn);
302- }
303-
304311 task (callback_type fn) : m_fn(fn) {}
305312
306313 virtual execution_state evaluate (T& blackboard) const override {
0 commit comments