20

我正在创建一个游戏,让玩家输入输入,改变一些状态,然后检查“目标值”是否为真(显然这个描述被大大简化了),我希望能够让这个目标值来自 if如果剩余的敌人数量等于零,则玩家的生命低于某个值。是否有任何“表达式类”可以保存一个简单的“value1 比较运算符 value2”并检查它?IE:

expression goal(x = 4);

如果没有,是否有人对我如何开发表达式课程有任何建议?

编辑:另一个(更接近我想要实现的目标)示例:

game.init(){ expression goal = FileRead(goalfile); }
game.checkstate(){ if(goal) exit(1); } //exit 1 is the games win state

//another more specific eg.:
class level1 { public: expression goal(total_enemies == 0); };
class level2 { public: expression goal(player.x == goal.x && player.y == goal.y); };
4

9 回答 9

24

动态表达式

如果您想从用户那里接收一个字符串并从中构建一个表达式,也许C++ 数学表达式库适合您的账单?

template<typename T>
void trig_function()
{
   std::string expression_string = "clamp(-1.0,sin(2 * pi * x) + cos(x / 2 * pi),+1.0)";
   T x;
   exprtk::symbol_table<T> symbol_table;
   symbol_table.add_variable("x",x);
   symbol_table.add_constants();

   exprtk::expression<T> expression;
   expression.register_symbol_table(symbol_table);

   exprtk::parser<T> parser;
   parser.compile(expression_string,expression);

   for (x = T(-5.0); x <= T(+5.0); x += 0.001)
   {
      T y = expression.value();
      printf("%19.15f\t%19.15f\n",x,y);
   }
}

也有可能嵌入脚本语言,例如LuaPython,这会给你(甚至)更多的权力。如果您正在编写游戏,这是需要考虑的事情,因为您可能想要编写大部分游戏的脚本。

如果您使用的是Qt,则可以使用QtScript (Javascript-ish) 来运行从 QObject 派生对象中读取(静态或动态)属性的表达式。

使用上述其中一个可以使您不必编写自己的解析器、AST 和评估器,但是对于一小部分运算符,如果您使用Boost.Spirit或其他一些不错的解析库,那么将某些东西组合在一起应该不会太难。

静态表达式

为了在一组预定义的表达式(即在编译时已知)之间进行选择,您应该将表达式存储在多态函数对象中。

对于 C++11,如果您可以使用,请使用std::function和 lambda 表达式。

std::function<bool (int, int)> expr = [](int a, int b) { a*2 < b };

对于早期的编译器,我建议使用Boost (boost::) 或 C++0x TR1 (std::) 中的函数和绑定,具体取决于您的编译器。此外,Boost.Lambda 在这里会有所帮助,因为它允许您构造和存储表达式以供以后评估。但是,如果您不熟悉 C++ 和模板(或函数式编程),它可能会吓到您。

有了它,你可以写

using namespace boost::lambda;
boost::function<bool (int, int)> myexpr1 = (_1 + _2) > 20;
boost::function<bool (int, int)> myexpr2 = (_1 * _2) > 42;
std::cout << myexpr1(4,7) << " " << myexpr2(2,5);

使用绑定,它看起来像:

boost::function<bool (Player&)> check = bind(&Player::getHealth, _1) > 20;
Player p1;
if (check(p1)) { dostuff(); }

check = bind(&Player::getGold, _1) < 42;
if (check(p1)) { doOtherStuff(); }
于 2009-06-10T21:37:09.873 回答
1

没有在运行时编译表达式的标准方法。你必须以其他方式做到这一点。

您可能会考虑使用脚本语言,如 Lua 或 Python,并将其嵌入到您的 C++ 中。这将使您的玩家能够按照您希望的程度进行编程。

于 2009-06-10T22:00:49.267 回答
0

不,没有那样的东西。也许表达式类有点太抽象了。用 IsReached() 方法定义各种目标类怎么样?

于 2009-06-10T21:34:39.117 回答
0

C++ 没有将此作为语言的一部分——在运行时无法访问解析程序的相同内容。

但是,我确信您可以使用许多第三方算术解析器库。

于 2009-06-10T21:35:13.747 回答
0

我认为您可以定义自己的类并使用“断言”关键字来解决问题,但我可能理解错误的问题。

http://www.cplusplus.com/reference/clibrary/cassert/assert/

于 2009-06-10T21:37:10.653 回答
0

为什么不构建自己的表达式类?

class GoalBase
{
    virtual bool goal() = 0;
};

class Enemies : public GoalBase 
{
   // ..
   private:
      int enemies_;

   public:
      Enemies(int start) : enemies_(start) {}
      void kill() { if (enemies_) --enemies_; }
      bool goal() { return enemies_ == 0; }
};

int main()
{
    Enemies enemiesToKill(5);
    enemiesToKill.kill();    

    // ..
    if (enemiesToKill.goal()) {
        // ..
    }

    return 0;
}

其他类可能有其他方法、参数、运算符等。发挥你的想象力。

于 2009-06-10T21:49:19.973 回答
0

在 C++ 中没有标准的方法来做到这一点。一种解决方案是编写自己的解析器。

我推荐的另一个解决方案:在你的程序中嵌入一个 Lua 解释器。Lua 是一种简单而强大的编程语言,它还具有极其轻量级 (<300kB) 且易于使用的解释器。在此处阅读介绍性文章:http: //www.ibm.com/developerworks/linux/library/l-embed-lua/index.html

将 Lua 嵌入你的游戏有许多不错的附带优势:

  • 您可以将其用作游戏的强大配置语言
  • 使用 Lua,您可以轻松创建一个命令行交互环境,非常适合测试和实验。例如,您将能够更改游戏引擎参数并立即看到效果,而无需重新编译。这对于“研究”项目或游戏编程特别方便。
于 2009-06-10T22:15:59.827 回答
0

静态表达式

(对Macke帖子的修改)

当您的表达式在编译时已知时,您可以使用 std::function. 但是,性能可能不是最佳的。

您可以使用 C++11 模板和宏在编译时自动注册测试并在运行时以(大概)最小的运行时开销执行它们。可以在此处找到概念验证实现。

In the long run, a language feature named "Contracts" could do the job. (N4415, N4435, N4378) Today, there are various libraries available to support contract programming.

于 2017-07-27T13:25:34.890 回答
-3

似乎没有那么多公认的 C++ 表达式评估库。我为CSVfix编写了自己的代码,您可以通过查看构成 CSVfix 源的一部分的 ALib 库中的a_expr.h和文件来理解它。a_expr.cpp评估者没有太多可以推荐自己的东西,除了它完成了这项工作并且(恕我直言)相当容易理解。

不幸的是,目前没有针对评估者的公开文档,并且根据我自己的经验法则,没有记录的内容不能重复使用。但是,单元测试显示了它是如何使用的,如果你有兴趣的话,源代码可能会给你一些关于实现你自己的评估器的想法。

于 2009-06-10T21:55:50.803 回答