feat(vf): extend Behavior
This commit is contained in:
1 parent
4e8e2799ed
commit
0c2bf7857b
1 file changed
+159
@@ -154,3 +154,162 @@ struct BehaviorContext {
|
||||
using BehaviorPredicate = std::function<bool(BehaviorContext&)>;
|
||||
using BehaviorAction = std::function<BehaviorStatus(BehaviorContext&)>;
|
||||
|
||||
// Base node. `tick` and `reset` are the non-virtual entry points: they keep the
|
||||
// trace and the cached verdict honest, then hand over to the subclass hooks.
|
||||
class BehaviorNode {
|
||||
public:
|
||||
explicit BehaviorNode(std::string nodeName);
|
||||
virtual ~BehaviorNode();
|
||||
|
||||
BehaviorNode(const BehaviorNode&) = delete;
|
||||
BehaviorNode& operator=(const BehaviorNode&) = delete;
|
||||
|
||||
BehaviorStatus tick(BehaviorContext& ctx);
|
||||
void reset();
|
||||
|
||||
const std::string& name() const { return nodeName; }
|
||||
BehaviorStatus lastStatus() const { return cachedStatus; }
|
||||
long long visitCount() const { return visits; }
|
||||
|
||||
virtual int childCount() const { return 0; }
|
||||
virtual BehaviorNode* childAt(int index) const;
|
||||
|
||||
protected:
|
||||
virtual BehaviorStatus onTick(BehaviorContext& ctx) = 0;
|
||||
virtual void onReset() {}
|
||||
|
||||
private:
|
||||
std::string nodeName;
|
||||
BehaviorStatus cachedStatus = BehaviorStatus::Failure;
|
||||
long long visits = 0;
|
||||
};
|
||||
|
||||
class ConditionNode : public BehaviorNode {
|
||||
public:
|
||||
ConditionNode(std::string nodeName, BehaviorPredicate predicate);
|
||||
|
||||
protected:
|
||||
BehaviorStatus onTick(BehaviorContext& ctx) override;
|
||||
|
||||
private:
|
||||
BehaviorPredicate predicate;
|
||||
};
|
||||
|
||||
class ActionNode : public BehaviorNode {
|
||||
public:
|
||||
ActionNode(std::string nodeName, BehaviorAction action);
|
||||
|
||||
protected:
|
||||
BehaviorStatus onTick(BehaviorContext& ctx) override;
|
||||
|
||||
private:
|
||||
BehaviorAction action;
|
||||
};
|
||||
|
||||
class BehaviorComposite : public BehaviorNode {
|
||||
public:
|
||||
explicit BehaviorComposite(std::string nodeName);
|
||||
|
||||
BehaviorComposite& add(std::unique_ptr<BehaviorNode> child);
|
||||
int childCount() const override { return static_cast<int>(children.size()); }
|
||||
BehaviorNode* childAt(int index) const override;
|
||||
|
||||
protected:
|
||||
std::vector<std::unique_ptr<BehaviorNode>> children;
|
||||
};
|
||||
|
||||
// Runs children in order until one succeeds. A child left Running is resumed
|
||||
// on the next tick; earlier children are not re-evaluated until the selector
|
||||
// settles on Success or Failure. Settling clears only the composite's own
|
||||
// cursor - a child's latched state (a cooldown, a repeat counter) survives, so
|
||||
// only BehaviorTree::reset wipes a whole tree back to its starting state.
|
||||
class SelectorNode : public BehaviorComposite {
|
||||
public:
|
||||
explicit SelectorNode(std::string nodeName);
|
||||
int resumeIndex() const { return runningChild; }
|
||||
|
||||
protected:
|
||||
BehaviorStatus onTick(BehaviorContext& ctx) override;
|
||||
void onReset() override;
|
||||
|
||||
private:
|
||||
int runningChild = 0;
|
||||
};
|
||||
|
||||
// Runs children in order until one fails. Same resumption rule as the selector.
|
||||
class SequenceNode : public BehaviorComposite {
|
||||
public:
|
||||
explicit SequenceNode(std::string nodeName);
|
||||
int resumeIndex() const { return runningChild; }
|
||||
|
||||
protected:
|
||||
BehaviorStatus onTick(BehaviorContext& ctx) override;
|
||||
void onReset() override;
|
||||
|
||||
private:
|
||||
int runningChild = 0;
|
||||
};
|
||||
|
||||
// Ticks every unfinished child each tick and latches the ones that settled.
|
||||
// Succeeds once `successThreshold` children have succeeded, fails once
|
||||
// `failureThreshold` have failed.
|
||||
class ParallelNode : public BehaviorComposite {
|
||||
public:
|
||||
ParallelNode(std::string nodeName, int successThreshold, int failureThreshold);
|
||||
|
||||
int successesSoFar() const;
|
||||
int failuresSoFar() const;
|
||||
|
||||
protected:
|
||||
BehaviorStatus onTick(BehaviorContext& ctx) override;
|
||||
void onReset() override;
|
||||
|
||||
private:
|
||||
int successThreshold;
|
||||
int failureThreshold;
|
||||
std::vector<BehaviorStatus> latched;
|
||||
std::vector<bool> settled;
|
||||
};
|
||||
|
||||
class DecoratorNode : public BehaviorNode {
|
||||
public:
|
||||
DecoratorNode(std::string nodeName, std::unique_ptr<BehaviorNode> child);
|
||||
|
||||
int childCount() const override { return wrapped ? 1 : 0; }
|
||||
BehaviorNode* childAt(int index) const override;
|
||||
|
||||
protected:
|
||||
BehaviorNode& child() const { return *wrapped; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<BehaviorNode> wrapped;
|
||||
};
|
||||
|
||||
class InverterNode : public DecoratorNode {
|
||||
public:
|
||||
InverterNode(std::string nodeName, std::unique_ptr<BehaviorNode> child);
|
||||
|
||||
protected:
|
||||
BehaviorStatus onTick(BehaviorContext& ctx) override;
|
||||
};
|
||||
|
||||
// Ticks the child once per tick and counts completions. Succeeds after
|
||||
// `repeatLimit` completions; with `stopOnFailure` a failing child ends the
|
||||
// repeat immediately.
|
||||
class RepeaterNode : public DecoratorNode {
|
||||
public:
|
||||
RepeaterNode(std::string nodeName, std::unique_ptr<BehaviorNode> child, int repeatLimit,
|
||||
bool stopOnFailure = false);
|
||||
|
||||
int completions() const { return completed; }
|
||||
|
||||
protected:
|
||||
BehaviorStatus onTick(BehaviorContext& ctx) override;
|
||||
void onReset() override;
|
||||
|
||||
private:
|
||||
int repeatLimit;
|
||||
bool stopOnFailure;
|
||||
int completed = 0;
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user