• Stars
    star
    440
  • Rank 95,628 (Top 2 %)
  • Language
    C++
  • License
    MIT License
  • Created 4 months ago
  • Updated 4 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Give a brain to your game's NPCs

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 {
      // ...
    }
};

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

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

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

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>(
  action_list<blackboard_type>(
    collect_food{},
    collect_wood{},
    collect_stone{},
    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};
};

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

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.

More Repositories

1

letlang

Functional language with a powerful type system.
Rust
157
star
2

astmaker

Build Abstract Syntax Trees and tree-walking models quickly in Rust.
Rust
118
star
3

shipp

Deadly simple package manager
Rust
94
star
4

sdl-game-engine

2D game engine based on SDL2
C++
91
star
5

logfmtxx

Header only C++23 structured logging library using logfmt
C++
68
star
6

tricorder

Automation the KISS way
Rust
50
star
7

doceaser

Interactive documentation with Markdown and HTMX made easier
Python
37
star
8

triotp

TriOTP, the OTP framework for Python Trio
Python
35
star
9

lispers

Educational project: How to implement a Lisp interpreter in Rust?
Rust
32
star
10

tshellout

Typescript Shell Out library, to simplify writing and composing shell commands for NodeJS
TypeScript
24
star
11

rustic_result

Result monad for Elixir inspired by Rust Result type
Elixir
21
star
12

elixir-k8s-love-story

Repository for the Medium series "Elixir and Kubernetes: A love story"
Elixir
20
star
13

easymd

Simple HTTP server to render markdown documents
Go
9
star
14

ooduck

Duck-Typing C library based on ooc.pdf
C
9
star
15

cream-browser

Web browser developped in C with GTK+ (same interface as Vimperator)
C
9
star
16

procfusion

Very simple process manager written in Rust for your Docker images
Rust
8
star
17

slightx

A free x86 operating system conforming to POSIX.
C
7
star
18

lemonldap-cli

Command Line tool to configure LemonLDAP::NG (depecrated: now maintained by the LemonLDAP::NG team)
Perl
7
star
19

link.crdt

Python implementation of Convergent Replicated Data Types
Python
7
star
20

airscript

Like Lua, but in Rust, and different
Rust
6
star
21

plstblog

Staitc blog generator written in Perl
Perl
6
star
22

fwallsh

Command line interface to configure your Linux router/server.
C
5
star
23

secure-user-data

Infrastructure to store, manage and access user data in a very secure manner.
Python
4
star
24

microci

MicroCI for lightweight self hosted continuous integration
Python
4
star
25

gin

Opinionated static website generator
TypeScript
3
star
26

graphbase

Graph oriented database
Erlang
3
star
27

manyssh

One command line to control multiple SSH connections.
Python
3
star
28

pcstats

Affiche les infos CPU/RAM/Disk du PC, dispo uniquement sous Linux
C
3
star
29

greenpkg

Little package manager inspired of Gentoo and BSD
C
2
star
30

yavm

Yet Another Virtual Machine
C
2
star
31

kickle-clone

Clone of the NES game "Kickle Cubicle"
C++
2
star
32

knowledgebase

Knowledge database organized in graph
JavaScript
2
star
33

rustic_maybe

Maybe monad for Elixir inspired by Rust Option type
Elixir
1
star
34

link.kvstore

Key/Value store generic API
Python
1
star
35

arecursion-js

Asynchronous recursion without maximum depth
JavaScript
1
star
36

hftforge

Forge in Python/Django
1
star
37

link.graph

Pure-Python graph database
Python
1
star
38

linkdd.github.io

linkdd's pages
HTML
1
star
39

link.wsgi

Fully configurable WSGI microframework
Python
1
star
40

wmfs-fifo

FIFO for WMFS2
C
1
star
41

linkdd-overlay

My own gentoo overlay
Shell
1
star
42

dirwatcher

Directory watcher for livereloading scripts
Python
1
star
43

xautostart

Python script to run all desktop entries in autostart directories
Python
1
star
44

notebook

Static Markdown Renderer
HTML
1
star
45

link.fulltext

Middleware feature for generic Fulltext-Index manipulation
Python
1
star
46

i3tools

Tools for i3wm
Python
1
star
47

9cal

CalDav server which respects the RFC
Python
1
star