Planners: goal representation
In Grail, planner goals are represented as collections of functions with bool
return type.
Why not just a single one, you ask?
If you define your goal as a list of subgoals, it’s much easier to come up with a sensible planner heuristic - you may use Hamming distance between the current state and the goal or penalize unsatisfied goal conditions in a different way.
Goal class
To bridge the abstract goal representation with your game’s world, Grail provides the Goal
class.
For reference, see the example below:
-
C++
-
C#
class MyGoal : public grail::planner::Goal
{
public:
MyGoal() = default;
// Inherited via Goal
virtual bool IsReached(const grail::AIEntity& entity) const override
{
//return true if the goal is reached, false otherwise
}
//this method specifies goal conditions in the abstract plan space
virtual void SetPlanSpaceConditions(grail::planner::Planner& planner, const grail::planner::ObjectIndexBinding&) const override
{
planner.PushCondition([](const grail::planner::WorldState& state)
{
return state.GetParameterValue<int>("int_param") > 0;
});
}
};
public class MyGoal : Goal
{
public override bool IsReached(AIEntity entity)
{
//return true if the goal is reached, false otherwise
}
public override void SetPlanSpaceConditions(Planner planner, ObjectIndexBinding binding)
{
planner.PushCondition(state => state.GetParameterValue<int>("int_param") > 0);
}
}
Goal selection
Grail does not make any assumptions on goal selection method.
The only thing you have to do is to provide an implementation of GoalSelector
class (or IGoalSelector
interface in C#).
For reference, see the example below:
-
C++
-
C#
class DummyGoalSelector : public grail::planner::GoalSelector
{
public:
DummyGoalSelector() = default;
virtual void UpdateGoal(grail::planner::IGoalAcceptor& goalAcceptor, grail::AIEntity& entity) override
{
//if no goal is currently chosen, set one
if (goalAcceptor.GetCurrentGoal() == nullptr)
{
goalAcceptor.SetNewGoal(std::make_unique<MyGoal>(), entity);
}
}
private:
std::string itemToCraft;
};
class DummyGoalSelector : IGoalSelector
{
public void UpdateGoal(IGoalAcceptor goalAcceptor, AIEntity entity)
{
//if no goal is currently chosen, set one
if (goalAcceptor.CurrentGoal == null)
{
goalAcceptor.SetNewGoal(new MyGoal(), entity);
}
}
};