【问题标题】:Lua preserving global valuesLua 保存全局值
【发布时间】:2012-11-21 09:12:47
【问题描述】:

我将 Lua 用于我的游戏引擎逻辑。我的主要游戏循环没有在 Lua 中完成。只有场景层次结构中的特殊节点附加了 Lua 脚本。这些脚本每帧执行一次。我面临的问题是我需要将全局变量值从一帧保存到另一帧。

我的临时解决方案如下所示:

finish = useBool("finish", false)
timer = useInt("timer", 0)
showTimer = useBool("showTimer", true)
startTimer = useInt("startTimer", 0)
play0 = useBool("play0", false)
play1 = useBool("play1", false)
play2 = useBool("play2", false)
play3 = useBool("play3", false)
delta = useInt("delta", 0)
gameOverTime = useInt("gameOverTime", 5000)
finishTime = useInt("finishTime", 5000)
checkPoint = useInt("checkPoint", 255)

<...> Game logic <...>

setInt("message", message);
setInt("checkPoint", checkPoint)
setInt("finishTime", finishTime)
setInt("gameOverTime", gameOverTime)
setInt("timer", timer)
setBool("play3", play3)
setBool("play2", play2)
setBool("play1", play1)
setBool("play0", play0)
setInt("startTimer", startTimer)
setBool("showTimer", showTimer)
setInt("timer", timer)
setBool("finish", finish);

我在开始时调用特殊方法从 C++ 中的哈希映射中检索全局变量,然后在脚本末尾再次设置它们。

有没有办法隐式地做到这一点?

不使用 Lua 作为主游戏循环是不是一个糟糕的设计?

【问题讨论】:

    标签: c++ lua


    【解决方案1】:

    好吧,虽然您的解决方案在技术上没有任何问题,但如果您最终使用大量全局变量(通常情况下应该避免的),您可能会开始注意到一些性能问题。

    话虽如此,还有改进的余地。例如:

    在脚本的开头,检查您的全局变量是否为nil。如果是,那么你可以初始化它,如果不是,这可能不是你第一次运行脚本,所以不要修改它。但这意味着很多讨厌的if-else 声明,很容易忘记。我们可以做得更好!

    我建议您查看《Lua 编程》一书中的 Chapter 14: The Environment。以下是简介中的简短引述:

    Lua 将其所有全局变量保存在一个常规表中,称为环境。 ...另一个(实际上是主要的)优点是我们可以像操作其他任何表一样操作该表。为了方便这种操作,Lua 将环境本身存储在一个全局变量 _G 中。 (是的,_G._G 等于 _G。)

    由于_G 是一个表,它也有一个元表,所以你可以定义__index__newindex 元方法来处理全局变量的访问和创建。您可以在section 14.2 中找到这方面的示例。去阅读整章吧,它不会那么长(如果你不熟悉元方法和元表,也可以看看chapter 13——这是 Lua 在灵活性方面真正闪耀的地方)。

    现在我们已经介绍了琐碎和普通的方法,让我们看看过度杀伤力的一端。作为一个例子,我将看看 Unity 的脚本编写方法。 Unity javascript 通常定义变量、函数和类型。任何在方法或类型范围之外定义的变量都会在帧之间持久化,因为脚本本身并不是每帧都执行的。相反,他们让脚本定义函数并在适当的时间调用函数。因此,如果您希望每帧都执行某些操作 - 您可以将其放入 Update 函数中。每个脚本都可以定义自己的 Update 函数,因为它有自己的范围。所以脚本引擎在每一帧都会遍历所有对象,检查脚本的作用域是否有Update 方法并调用它。

    回到 Lua - 这样的解决方案将涉及为每个对象/脚本/无论您的节点是什么创建单独的环境。然后,您的主循环将遍历所有节点并在其环境中运行一个函数,而不是每帧执行附加到您的节点的脚本。您还可以切换环境,因此您可以在执行之前将全局环境设置为节点的 env,然后在完成后切换回来。这允许您的脚本在它们认为合适的时候使用全局变量,让它们在帧之间持久化,并排除名称冲突或全局命名空间污染的可能性。此外,您可以使用元方法将节点的环境嵌套在实际的全局环境中或使用辅助方法的 API 环境中(基本上,如果 __index 没有找到它在 parent 中查找的内容)。

    【讨论】:

      猜你喜欢
      • 2018-12-08
      • 2019-03-01
      • 2014-09-27
      • 2018-03-04
      • 1970-01-01
      • 2019-12-22
      • 2013-03-28
      • 2019-08-21
      • 1970-01-01
      相关资源
      最近更新 更多