我如何以依赖GOAP中变量的方式定义动作池?

问题描述 投票:0回答:1

我正在尝试在游戏中实施GOAP。该游戏是一种模拟类型的游戏,不仅会从GOAP中受益,而且从本质上来说,它是基于代理可以执行的操作范围的要求。

我有以下代码。这里没有计划者,只有动作,状态等的定义

#include <vector>
#include <string>
#include <unordered_map>

class Condition
{
public:

    bool operator()(const int value) const
    {
        return m_min <= value && value <= m_max;
    }

    enum class OP : std::uint8_t
    {
        EE, LT, GT, LE, GE
    };

    Condition(const int min, const int max, const OP op)
    :
        m_op(op),
        m_min(min),
        m_max(max)
    {}

    static Condition CreateEE(const int goal)
    {
        return Condition(goal, goal, OP::EE);
    }

    static Condition CreateGT(const int goal)
    {
        return Condition(goal+1, std::numeric_limits<int>::max(), OP::GT);
    }

    static Condition CreateLT(const int goal)
    {
        return Condition(std::numeric_limits<int>::min(), goal-1, OP::LT);
    }

    static Condition CreateGE(const int goal)
    {
        return Condition(goal, std::numeric_limits<int>::max(), OP::GT);
    }

    static Condition CreateLE(const int goal)
    {
        return Condition(std::numeric_limits<int>::min(), goal, OP::LT);
    }

private:

    OP m_op;
    int m_min;
    int m_max;
};

class Effect
{
public:

    enum class OP : std::uint8_t
    {
        ADD, SUB, MUL, DIV, EQ
    };

    Effect(OP op, int value)
    :
        m_op(op),
        m_value(value)
    {

    }

protected:
    OP m_op;
    int m_value;
};

class Action
{
public:
    void AddPrereq(const std::string& name, Condition value)
    {
        m_prereqs.emplace_back(name,value);
    }

    void AddEffect(const std::string& name, Effect effect)
    {
        m_effects.emplace_back(name,effect);
    }

    void SetCost(const float cost)
    {
        m_cost = cost;
    }

private:

    float m_cost;

    std::vector<std::pair<std::string,Condition>> m_prereqs;
    std::vector<std::pair<std::string,Effect>> m_effects;
};

class WorldState
{
public:

    void AddFact(const std::string& name, const int value)
    {
        m_facts[name] = value;
    }

private:

    std::unordered_map<std::string,int> m_facts;
};

class GoalState
{
public:

    void AddCondition(const std::string& name, const Condition condition)
    {
        m_conditions.emplace_back(name, condition);
    }

private:
    std::vector<std::pair<std::string,Condition>> m_conditions;
};

int main()
{
    Action goTo;
    goTo.AddEffect("isAtPosition", Effect(Effect::OP::EQ, 1));

    Action pickUp;
    pickUp.AddPrereq("isAtPosition", Condition::CreateEE(1));
    pickUp.AddEffect("itemInPossession", Effect(Effect::OP::EQ, 1));

    Action drop;
    drop.AddPrereq("itemInPossession", Condition::CreateEE(1));
    drop.AddEffect("itemAtPosition", Effect(Effect::OP::EQ, 1));

    WorldState ws;
    ws.AddFact("itemAtPosition", 0);

    GoalState gs;
    gs.AddCondition("itemAtPosition", Condition::CreateGE(1));

    return 0;
}

目前,我仅使用布尔值,因为对于我的测试用例,它是关于代理移动到某个位置,拾取一个项目并将其移动到另一个位置。稍后,目标可能是移动n个项目或其他内容。

动作将是:

  1. 转到(将业务代表置于职位上)
  2. 提货(拥有物品)
  3. 转到(将业务代表置于职位上)
  4. 丢弃(放置项目中的项目)达到目标!

但是我如何在这里两次使用Goto操作?设置“ isAtPosition”变量的效果是相同的。我需要为“ isAtItemPosition”和“ isAtDestinationPosition”创建一个新的状态变量吗?

因为似乎我将为每个可能的目标有效地制定特定的行动,而我的效果是确定所有可能的行动顺序。

如何编码状态信息,以便可以将池中的相同操作应用于不同的阶段,从而产生不同的效果? (转到项目位置与转到目标位置)。

artificial-intelligence path-finding game-ai
1个回答
0
投票

是,如果只有布尔值,则需要对每个位置进行单独的操作。

[如果可以,我会考虑使用功能更强大的表示形式,例如STRIPSPDDL。这将使描述一些更为复杂的场景变得更加容易,并且还具有额外的好处,即您可以使用现成的求解器来为您的代理制定计划。

在PDDL中,您可以执行操作(move ?agent ?from ?to),前提是代理已在位置?from,并且执行该操作后,他们将在位置?to。要拾取一个对象,您可以使(pick-up ?agent ?object)带有前提条件,即代理和对象都在同一位置。这比固定的布尔动作更通用,并且将允许以后的扩展更容易。

© www.soinside.com 2019 - 2024. All rights reserved.