Skip to content

active-logic/xgoap

Repository files navigation

Pre-release - APIs are more likely to change during the pre-release period.

Build Status codecov

Beyond G.O.A.P

A fresh take on Goal oriented action planning.

In GOAP, actions have preconditions, effects, and a cost. Boilerplate? Have a look.

public Cost ChopLog(){
    if(!hasAxe) return false;  // Precondtion
    hasFirewood = true;        // Effect
    return 4;                  // Cost
}

Use A* or, if no cost function available, BFS.

  • Engine agnostic models - test without pain.
  • .NET Core compatible
  • Unity integration with UPM support
  • Demo project to help you get started
  • [COMING SOON] integration with the BT Framework of Awesome, Active Logic 🚀

Install

Clone the repository and add the package to your project as normal.

For Unity 3D:

  • Add xgoap/package.json via package manager > + > add package from disk.
  • Alternatively, add "com.activ.goap": "https://github.com/active-logic/xgoap.git" to Packages/manifest.json

Getting started

Planning requires a model and a goal; if available, also provide a heuristic. I will borrow Brent Owens' woodcutter example.

A woodcutter has the GetAxe, ChopLog and CollectBranches actions. Here is our implementation of the woodcutter planning model:

using Activ.GOAP;

public class WoodChopper : Agent, Clonable<WoodChopper>{

    public bool hasAxe, hasFirewood;
    Option[] opt;  // Caching reduces array alloc overheads

    public Option[] Options()
    => opt = opt ?? new Option[]{ ChopLog, GetAxe, CollectBranches };

    public Cost GetAxe(){
        if(hasAxe) return false;
        hasAxe = true;
        return 2;
    }

    public Cost ChopLog() => hasAxe ? (Cost)(hasFirewood = true, 4f) : (Cost)false;

    public Cost CollectBranches() => (hasFirewood = true, 8);

    // Clonable<WoodChopper>

    public WoodChopper Allocate() => new WoodChopper();

    public WoodChopper Clone(WoodChopper x){
        x.hasAxe      = hasAxe;
        x.hasFirewood = hasFirewood;
        return x;
    }

    // Override for correctness (don't compare refs) and faster hashes

    override public bool Equals(object other) => other is WoodChopper that
        && hasAxe == that.hasAxe && hasFirewood == that.hasFirewood;

    override public int GetHashCode() => (hasAxe ? 1 : 0)
                                       + (hasFirewood ? 2 : 0);

}

Run the model and get the next planned action:

var chopper = new WoodChopper();
var solver  = new Solver<WoodChopper>();
var next    = solver.Next(chopper, goal: (x => x.hasFirewood, null));

Parametric actions are supported; they are concise and type safe. Check the Baker example.

Quick and simple Unity integration via GameAI.cs - for details, read here.

Ready to GOAP? Follow the guide.

Getting involved

If you'd like to get involved, consider opening (or fixing) an issue. Your support is appreciated!

Send a tip