Lua如何使一个脚本在不同的脚本加载中保持其值?

我目前遇到的问题是有几个敌人共享同一个A.I.脚本,但还有另一个对象会执行不同的操作。脚本中的函数被称为AILogic。我希望这些敌人能够独立移动,但这很难。我尝试了以下方法:

1)在敌人的构造函数中调用dofile,然后在每个游戏循环的Update函数中调用它的脚本函数。问题是Lua只使用最后一个构造的敌人的脚本,所以所有敌人在Update函数中运行相同的脚本。因此,我描述的这个对象不使用相同的A.I.脚本正在使用其他敌人的脚本。

2)在Update函数中调用dofile,然后立即调用它的脚本函数。问题是dofile在每个对象的更新函数中都被调用,因此在AILogic函数运行并更新该脚本的数据后,当为另一个敌人调用dofile时整个过程会被重置。我最大的问题在于是否有一种方法可以保留脚本中的值,即使我切换到运行不同的脚本。

我已经阅读了关于Lua函数环境的文章,但我不确定如何正确实现它们。这是正确的方向吗?任何建议都将不胜感激,谢谢。

编辑:我还考虑在Lua脚本之外创建一个单独的地方来存储数据。

编辑2:添加了一些示例代码。(只是用于获得功能运行的测试)。

-- 粘液的脚本

local count = 0;

function AILogic(Slime)
  -- 让史莱姆在圆形(四边形)中移动
  if count < 4 then
    Slime: MoveDir(0);
  elseif count < 8 then
    Slime: MoveDir(2);
  elseif count < 12 then
    Slime: MoveDir(1);
  elseif count < 16 then
    Slime: MoveDir(3);
  else
    count = 0;
  end
  count = count + 1;
end

原文链接 https://stackoverflow.com/questions/2353431

点赞
stackoverflow用户282658
stackoverflow用户282658

这个问题的官方参考文献是链接文本。简单解释一下,我们将从网站中的以下代码开始:

a = 1
local newgt = {}        -- create new environment
setmetatable(newgt, {__index = _G})
setfenv(1, newgt)    -- set it

第一行设置了(全局)变量“a”。您可以将其视为为代码设置默认值。(请记住,Lua中除非您使用“local”声明它们,否则所有变量都是全局的。)

下一行创建了一个表,这将是您的新环境。它是局部的,只能在您执行的函数/块中使用,因此不会被任何其他运行的程序所破坏。

第三行是魔法的开端。要理解它,您必须理解元方法。然而在本质上,您正在使用Lua的元魔法来确保在您即将使用的函数环境中未定义的全局名称在您之前的全局环境的上下文中解析。基本意思是,如果你在你的函数环境中使用了一个没有定义的名字,Lua就会自动地搜索你曾经拥有的全局环境中的名字。(简言之,是继承。)

第四行是你想要的地方。Setfenv(1,...)表示这将为您当前的函数更改环境。(对于调用函数,您可以使用2,对于调用函数的调用程序,您可以使用3等。一直往上。)第二参数是您刚刚设置的表格,包括旧行为的继承。您的函数现在正在执行一个新的全局环境中。它有旧环境中所有的名称和值方便使用(包括函数和您放置在其中的全局变量“a”)。但是如果您写入一个名称,则不会覆盖全局状态。它将覆盖您的本地副本。

考虑以下后续代码:

a = 10
b = 20

现在,您已经使您的函数环境表如下所示:

{a = 10, b=20}

您的“全局”环境简而言之只包含两个变量:a(值为10)和b(值为20)。当您稍后访问“a”时,您将获得您的本地副本,其中包括10个旧全局值存储在您的元表中,现在已被掩盖,并且仍设置为1-如果您访问“b”,您将获得20,即使最初的全局状态可能甚至没有变量“b”可访问。您仍然能够访问此点之前定义的所有函数等。


编辑以添加调试OP问题的测试代码。

我将以下代码放入“junk.lua”中:

a = 1
local newgt = {}
setmetatable(newgt, {__index = _G})
setfenv(1, newgt)
print(a)
a = 10
print(a)
print(newgt)

它的输出如下:

$ lua junk.lua
1
10
table: 0x976d040

这是使用Lua 5.1.4。您看到的输出是什么?

2010-03-01 03:36:26
stackoverflow用户258523
stackoverflow用户258523

lua 解释器将每行作为单独的代码块运行,这意味着局部变量只在该行中有效,因此示例代码不能像原样运行。要么一次性运行所有代码(没有换行),不使用局部变量,或者在 do ... end 块中运行。

至于开篇的问题,如果你想共享完全相同的函数(即运行时完全相同的函数),则函数需要将数据作为参数传递。但是,如果您可以使用相同的代码但不同的(运行时)函数,则可以使用闭包来保存本地/个体数据。

local function make_counter()
    local count = 0

    return function ()
        local c = count
        count = count + 1
        return c
    end
end

c1 = make_counter()
c2 = make_counter()
c3 = make_counter()

print(c1())
print(c1())
print(c1())
print(c1())
print(c2())
print(c3())
print(c2())
print(c3())
print(c2())
print(c3())

或者,您可以每次调用函数时玩弄其环境,但这只对某些情况有效(取决于函数的内部实现)。

2010-03-01 12:27:38