Giter VIP home page Giter VIP logo

aitoolkit's Introduction

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.1"
    }
  ]
}

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.

aitoolkit's People

Contributors

jankoy avatar linkdd avatar sykim2312 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

aitoolkit's Issues

intended pattern for executing GOAP plans

First off, great work on this library!

I'm a bit confused as to the intended pattern for actually executing the plans that come out of this GOAP implementation. If I'm understanding the API correctly, it seems like the apply_effects function may run more than once as part of the pathfinding process. That would seemingly make it a poor fit to hook into for eg updating an agent's nav target, or having them attack another agent, which are operations you only want to execute when you have a full plan.

Is my understanding here accurate, or am I misunderstanding how your implementation works? I'm also not seeing a way to get eg a queue of actions out of the planner, but maybe apply_effects is intended to work as essentially a visitor for that purpose?

Edit: Just noticed the dry_run argument - not sure how I missed that haha. Is that meant to differentiate between the planning process and the execution process? If so, is the blackboard meant to contain a reference to the relevant agent/actor/etc, with the planner and actions being single-instance for the application, or are they meant to be instanced for each agent? If the former, is the planner thread-safe?

Godot integration

Hello can i using it in godot please

where found some how to to using it ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.