Skip to content

Commit 675fdd6

Browse files
authored
🔀 Merge pull request #6 from linkdd/fix-memory-ownership
♻️ Fix memory ownership
2 parents 5df3bd9 + ee320fd commit 675fdd6

File tree

9 files changed

+411
-328
lines changed

9 files changed

+411
-328
lines changed

README.md

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ Create your simple state machine:
8787
auto simple_bb = blackboard_type{};
8888
auto simple_fsm = simple_machine<blackboard_type>();
8989
90-
simple_fsm.set_state(std::make_shared<state_dummy>(), simple_bb);
90+
simple_fsm.set_state(state_dummy{}, simple_bb);
9191
simple_fsm.pause(simple_bb);
9292
simple_fsm.resume(simple_bb);
9393
simple_fsm.update(simple_bb);
@@ -99,8 +99,8 @@ Or with a stack state machine:
9999
auto stack_bb = blackboard_type{};
100100
auto stack_fsm = stack_machine<blackboard_type>{};
101101

102-
stack_fsm.push_state(std::make_shared<state_dummy>(), stack_bb);
103-
stack_fsm.push_state(std::make_shared<state_dummy>(), stack_bb);
102+
stack_fsm.push_state(state_dummy{}, stack_bb);
103+
stack_fsm.push_state(state_dummy{}, stack_bb);
104104

105105
stack_fsm.update(stack_bb);
106106

@@ -129,16 +129,18 @@ struct blackboard_type {
129129
Then, create your tree:
130130

131131
```cpp
132-
auto tree = seq<blackboard_type>::make({
133-
check<blackboard_type>::make([](const blackboard_type& bb) {
134-
// check some condition
135-
return true;
136-
}),
137-
task<blackboard_type>::make([](blackboard_type& bb) {
138-
// perform some action
139-
return execution_state::success;
140-
})
141-
});
132+
auto tree = seq<blackboard_type>(
133+
node_list<blackboard_type>(
134+
check<blackboard_type>([](const blackboard_type& bb) {
135+
// check some condition
136+
return true;
137+
}),
138+
task<blackboard_type>([](blackboard_type& bb) {
139+
// perform some action
140+
return execution_state::success;
141+
})
142+
)
143+
);
142144
```
143145
144146
Finally, evaluate it:
@@ -148,7 +150,7 @@ auto blackboard = blackboard_type{
148150
// ...
149151
};
150152
151-
auto state = tree->evaluate(blackboard);
153+
auto state = tree.evaluate(blackboard);
152154
```
153155

154156
For more informations, consult the
@@ -226,12 +228,14 @@ class collect_gold final : public action<blackboard_type> {
226228
Finally, create an evaluator and run it:
227229

228230
```cpp
229-
auto evaluator = evaluator<blackboard_type>{
230-
std::make_shared<collect_food>(),
231-
std::make_shared<collect_wood>(),
232-
std::make_shared<collect_stone>(),
233-
std::make_shared<collect_gold>()
234-
};
231+
auto evaluator = evaluator<blackboard_type>(
232+
action_list<blackboard_type>(
233+
collect_food{},
234+
collect_wood{},
235+
collect_stone{},
236+
collect_gold{}
237+
)
238+
);
235239

236240
auto blackboard = blackboard_type{};
237241
evaluator.run(blackboard);
@@ -295,17 +299,20 @@ class chop_tree final : public action<blackboard_type> {
295299
Finally, create a plan and run it:
296300
297301
```cpp
298-
auto actions = std::vector<action_ptr<blackboard_type>>{
299-
std::make_shared<get_axe>(),
300-
std::make_shared<chop_tree>()
301-
};
302302
auto initial = blackboard_type{};
303303
auto goal = blackboard_type{
304304
.has_axe = true,
305305
.wood = 3
306306
};
307307
308-
auto p = planner<blackboard_type>(actions, initial, goal);
308+
auto p = planner<blackboard_type>(
309+
action_list<blackboard_type>(
310+
get_axe{},
311+
chop_tree{}
312+
),
313+
initial,
314+
goal
315+
);
309316
310317
auto blackboard = initial;
311318
while (p) {

include/aitoolkit/behtree.hpp

Lines changed: 78 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -71,38 +71,44 @@ Next, create the tree:
7171
```cpp
7272
using 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
108114
Finally, evaluate the tree:
@@ -116,19 +122,21 @@ auto bb = blackboard_type{
116122
};
117123
118124
while (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+
132140
namespace 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

Comments
 (0)