AI Toolkit
Loading...
Searching...
No Matches
AI Toolkit

tests docs license version

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 -Iaitoolkit/include main.cpp -o mygame

NB: This library is compatible with C++20.

Or using Shipp, add it to your dependencies:

{
"name": "myproject",
"version": "0.1.0",
"dependencies": [
{
"name": "aitoolkit",
"url": "https://github.com/linkdd/aitoolkit.git",
"version": "v0.5.0"
}
]
}

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 {
// ...
}
};
A state of the FSM.
Definition fsm.hpp:169

Create your simple state machine:

auto simple_bb = blackboard_type{};
auto simple_fsm = simple_machine<blackboard_type>();
simple_fsm.set_state(state_dummy{}, simple_bb);
simple_fsm.pause(simple_bb);
simple_fsm.resume(simple_bb);
simple_fsm.update(simple_bb);
A simple FSM.
Definition fsm.hpp:198

Or with a stack state machine:

auto stack_bb = blackboard_type{};
auto stack_fsm = stack_machine<blackboard_type>{};
stack_fsm.push_state(state_dummy{}, stack_bb);
stack_fsm.push_state(state_dummy{}, stack_bb);
stack_fsm.update(stack_bb);
stack_fsm.pop_state(stack_bb);
stack_fsm.pop_state(stack_bb);
A stack FSM.
Definition fsm.hpp:273
void push_state(S state, T &blackboard)
Enters in a new state, pausing the previous one (if any).
Definition fsm.hpp:279

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:

node_list<blackboard_type>(
check<blackboard_type>([](const blackboard_type& bb) {
// check some condition
return true;
}),
task<blackboard_type>([](blackboard_type& bb) {
// perform some action
return execution_state::success;
})
)
);
Check node, will return success if the callback returns true.
Definition behtree.hpp:281
Sequence node, will execute all children in order until one fails.
Definition behtree.hpp:202
Task node, will execute the callback and return the result.
Definition behtree.hpp:306

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;
}
};
Base abstract class for all actions.
Definition utility.hpp:128

Finally, create an evaluator and run it:

action_list<blackboard_type>(
collect_food{},
collect_wood{},
collect_stone{},
collect_gold{}
)
);
auto blackboard = blackboard_type{};
evaluator.run(blackboard);
Evaluate a set of actions and apply the best one.
Definition utility.hpp:171
void run(T &blackboard) const
Find the best action and apply it to the blackboard.
Definition utility.hpp:181

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};
};

NB: The blackboard needs to be comparable (a == b) and hashable.

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, bool dry_run) 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, bool dry_run) const override {
blackboard.wood += 1;
}
};
An action that can be performed on a blackboard.
Definition goap.hpp:201

Finally, create a plan and run it:

auto initial = blackboard_type{};
auto goal = blackboard_type{
.has_axe = true,
.wood = 3
};
auto p = planner<blackboard_type>(
action_list<blackboard_type>(
get_axe{},
chop_tree{}
),
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.