AI Toolkit: Give a brain to your game's NPCs, a header-only C++ library
source link: https://github.com/linkdd/aitoolkit
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Repository files navigation
AI Toolkit
AI Toolkit is a header-only C++ library which provides tools for building the brain of your game's NPCs.
It provides:
- Finite State Machines
- Behavior Tree
- Utility AI
- Goal Oriented Action Planning
Why this project? Well, I wrote about it here.
Installation
Add the include
folder of this repository to your include paths.
Or add it as a submodule:
$ git submodule add https://github.com/linkdd/aitoolkit.git
$ g++ -std=c++23 -Iaiotoolkit/include main.cpp -o mygame
NB: This library is compatible with C++20.
Usage
Finite State Machine
First, include the header:
#include <aitoolkit/fsm.hpp>
using namespace aitoolkit::fsm;
Then, create your blackboard type:
struct blackboard_type {
// ...
};
Then, create a state type for each of your states:
class state_dummy final : public state<blackboard_type> {
public:
virtual void enter(blackboard_type& blackboard) override {
// ...
}
virtual void exit(blackboard_type& blackboard) override {
// ...
}
virtual void pause(blackboard_type& blackboard) override {
// ...
}
virtual void resume(blackboard_type& blackboard) override {
// ...
}
virtual void update(blackboard_type& blackboard) override {
// ...
}
};
Create your simple state machine:
auto simple_bb = blackboard_type{};
auto simple_fsm = simple_machine<blackboard_type>();
simple_fsm.set_state(std::make_shared<state_dummy>(), simple_bb);
simple_fsm.pause(simple_bb);
simple_fsm.resume(simple_bb);
simple_fsm.update(simple_bb);
Or with a stack state machine:
auto stack_bb = blackboard_type{};
auto stack_fsm = stack_machine<blackboard_type>{};
stack_fsm.push_state(std::make_shared<state_dummy>(), stack_bb);
stack_fsm.push_state(std::make_shared<state_dummy>(), stack_bb);
stack_fsm.update(stack_bb);
stack_fsm.pop_state(stack_bb);
stack_fsm.pop_state(stack_bb);
Behavior Tree
First, include the header:
#include <aitoolkit/behtree.hpp>
using namespace aitoolkit::bt;
Then, create your blackboard type:
struct blackboard_type {
// ...
};
Then, create your tree:
auto tree = seq<blackboard_type>::make({
check<blackboard_type>::make([](const blackboard_type& bb) {
// check some condition
return true;
}),
task<blackboard_type>::make([](blackboard_type& bb) {
// perform some action
return execution_state::success;
})
});
Finally, evaluate it:
auto blackboard = blackboard_type{
// ...
};
auto state = tree->evaluate(blackboard);
For more informations, consult the documentation.
Utility AI
First, include the header file:
#include <aitoolkit/utility.hpp>
using namespace aitoolkit::utility;
Then, create a blackboard type:
struct blackboard_type {
int food{0};
int wood{0};
int stone{0};
int gold{0};
};
Next, create a class for each action that you want to be able to perform:
class collect_food final : public action<blackboard_type> {
public:
virtual float score(const blackboard_type& blackboard) const override {
return 50.0f;
}
virtual void apply(blackboard_type& blackboard) const override {
blackboard.food += 1;
}
};
class collect_wood final : public action<blackboard_type> {
public:
virtual float score(const blackboard_type& blackboard) const override {
return 150.0f;
}
virtual void apply(blackboard_type& blackboard) const override {
blackboard.wood += 1;
}
};
class collect_stone final : public action<blackboard_type> {
public:
virtual float score(const blackboard_type& blackboard) const override {
return -10.0f;
}
virtual void apply(blackboard_type& blackboard) const override {
blackboard.stone += 1;
}
};
class collect_gold final : public action<blackboard_type> {
public:
virtual float score(const blackboard_type& blackboard) const override {
return 75.0f;
}
virtual void apply(blackboard_type& blackboard) const override {
blackboard.gold += 1;
}
};
Finally, create an evaluator and run it:
auto evaluator = evaluator<blackboard_type>{
std::make_shared<collect_food>(),
std::make_shared<collect_wood>(),
std::make_shared<collect_stone>(),
std::make_shared<collect_gold>()
};
auto blackboard = blackboard_type{};
evaluator.run(blackboard);
Goal Oriented Action Planning
First, include the header file:
#include <aitoolkit/goap.hpp>
using namespace aitoolkit::goap;
Then, create a blackboard class that will hold the state of the planner:
struct blackboard_type {
bool has_axe{false};
int wood{0};
};
Next, create a class for each action that you want to be able to perform:
class get_axe final : public action<blackboard_type> {
public:
virtual float cost(const blackboard_type& blackboard) const override {
return 1.0f;
}
virtual bool check_preconditions(const blackboard_type& blackboard) const override {
return !blackboard.has_axe;
}
virtual void apply_effects(blackboard_type& blackboard) const override {
blackboard.has_axe = true;
}
};
class chop_tree final : public action<blackboard_type> {
public:
virtual float cost(const blackboard_type& blackboard) const override {
return 1.0f;
}
virtual bool check_preconditions(const blackboard_type& blackboard) const override {
return blackboard.has_axe;
}
virtual void apply_effects(blackboard_type& blackboard) const override {
blackboard.wood += 1;
}
};
Finally, create a plan and run it:
auto actions = std::vector<action_ptr<blackboard_type>>{
std::make_shared<get_axe>(),
std::make_shared<chop_tree>()
};
auto initial = blackboard_type{};
auto goal = blackboard_type{
.has_axe = true,
.wood = 3
};
auto p = planner<blackboard_type>(actions, initial, goal);
auto blackboard = initial;
while (p) {
p.run_next(blackboard); // will mutate the blackboard
}
For more informations, consult the documentation.
Documentation
The documentation is available online here.
You can build it locally using doxygen:
$ make docs
License
This library is released under the terms of the MIT License.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK