【问题标题】:Per-entity Lua scripts in games?游戏中的每实体 Lua 脚本?
【发布时间】:2015-12-21 22:21:00
【问题描述】:

我在我的 C++ 游戏中使用 Lua 作为脚本。我希望能够将脚本附加到实体,并根据脚本中定义的函数注册回调,以便在适当的时间运行脚本函数。

我相信我可以通过将“脚本”制作成表格来封装不同的脚本。基本上,... lua source code ... 会变成ScriptName = { ... lua source code ... }。然后我不会调用func(),而是调用ScriptName.func(),因此定义相同函数(也就是注册相同事件)的两个脚本不会互相践踏。

我现在的问题是封装共享相同脚本的不同实体。显然我不希望它们共享变量,但是就我现在所做的而言,脚本定义的任何变量都将由该脚本的每个实例共享,这真的很糟糕。我可以在源代码级别尝试类似于我的上述解决方案的方法,方法是在编译之前用EntityID.ScriptName = { ... } 包装每个脚本。有人告诉我有更好的方法,但我不知道。

另一个因素是脚本需要能够引用与特定实体相关的实体和脚本/组件。如果我使用上述方法,最好的解决方案是将实体 ID 作为可以引用特定于该实体的表的字符串传递,我认为?在这一点上,我真的不知道自己在做什么。

【问题讨论】:

  • 也许切换到更多的对象概念,换句话说代码可以与实例重用?我在“智力练习”之后从“脚本”概念切换到 Groovy 平台中的对象表示法。语言不同,问题相似(抱歉,没有英文拼写)

标签: c++ lua entity game-engine


【解决方案1】:

为了让脚本与 C++ 对象交互,典型的方法是让 C++ 代码将对象作为用户数据(指针的包装器)公开给 Lua,并提供脚本可以调用的 C++ 函数,传递用户数据作为参数。在 C++ 代码中,该 userdata 为您提供了函数应该操作的对象。它相当于一个“this”指针。

您通常通过将 C++ 函数放入与用户数据关联的元表中来实现这一点,这样它们就可以像 Lua 代码中的方法一样被调用(即objectIGotFromCpp:someMethod('foo')

ScriptName.func(),因此定义相同函数(也就是注册相同事件)的两个脚本不会互相践踏。

而不是依赖于访问全局变量或命名约定等。简单地提供一个回调,Lua 脚本可以使用它来注册事件。

如果我使用上述方法,最好的解决方案是将实体 ID 作为字符串传递

没有理由。 C++ 代码中的实体是指向堆上对象的指针。您可以将该指针作为用户数据直接传递给 Lua。 Lua 可以将它传回你的 C++ 代码,让你直接访问对象,而不是通过一些对象到 ID 的映射。

【讨论】:

  • 这并没有真正解决我主要关心的问题,这是多个实体共享的单个脚本。每个脚本都会定义变量,每个共享一个脚本的实体会互相践踏。
  • 当你编译一个脚本时,它会产生一个函数。函数可以传递局部变量的参数,并且可以在其范围内创建新的局部变量。与几乎所有语言中的函数一样,这些局部变量对于函数的每次调用都是唯一的。它们保存在单独的堆栈帧上。那么在特定实体的上下文中运行脚本意味着是什么意思?如果您将实体传递给脚本(即,您使用要操作的实体调用脚本的函数),它修改的任何局部变量都不会影响脚本的其他调用。
  • 如果您谈论的是由脚本访问/修改的 全局 变量,那么它们当然会被践踏。这就是为什么globals are bad
  • 我需要能够从一个调用到下一个调用保持某种状态。我还需要能够定义可以从游戏编辑器或不同实体的脚本设置的参数。有点像在一个类中定义变量——它们不是全局的,因为它们属于那个类,但它们的状态在函数调用中保持不变,并且独立于该类的任何其他实例。
  • 您所描述的内容听起来像函数式编程,在幕后不跟踪任何状态,并且每个变量或指针都作为参数传递或返回值给函数。我对函数式编程没有兴趣。
猜你喜欢
  • 2011-06-15
  • 1970-01-01
  • 1970-01-01
  • 2014-08-26
  • 2020-10-17
  • 2021-07-05
  • 2010-12-23
  • 2020-11-08
  • 1970-01-01
相关资源
最近更新 更多