如何结束Lua中的循环协程?

时间:2014-02-18 19:33:16

标签: lua roblox

我目前正在使用Roblox(使用Lua)进行游戏。它基本上由几个小游戏组成。在每轮开始时,游戏中的所有玩家都被放入桌子并被传送到一个区域。这是协程开始发挥作用的地方。随着回合的进行,我想要一个协程开始。协程每一秒检查玩家的健康状况是否低于零,并将其从currentPlayer表中移除(如果是)。

很抱歉,如果我没有正确描述问题,但协程将不会产生。我之前没有使用过协同程序,所以我可能试图以错误的方式使用它。我知道你们大多数人都不熟悉Roblox,但是Lua的语法是一样的。

有人可以举个例子说明我将如何结束循环协程吗?

currentPlayers = {}
roundTime = 60

local lookForWinners = coroutine.create(function()
  while coroutine.running do
    wait(1)
    for i, v in pairs(currentPlayers) do
      if v.Character.Humanoid.Health <= 0 then
        table.remove(currentPlayers, v)
      end
    end
  end
end)


while wait() do
  repeat display("Two or more players need to be in the game.", 1) until #_G.plrs > 1 --Ignore, just checks if two+ players are in game.
  display("Picking a map...", 3) pickMap()
  teleport(0, 500, 0)
  coroutine.resume(lookForWinners)
  wait(roundTime)
  print("Round over")
  coroutine.yield(lookForWinners)
end

2 个答案:

答案 0 :(得分:4)

Lua是一种单线程语言。协同程序不会导致函数并行执行。

协程实际上只是一种创建一个可以暂停自己执行的函数的方法(使用coroutine.yield),可以从外部恢复(使用coroutine.resume)。 There is no "coroutine.running":在任何给定时间只有一条线“正在运行”。

如果Roblox意味着您使用wait()跳出Lua线程,您可以将其写为一系列循环来检查其状况,然后调用wait()

local currentPlayers={}
local roundTime = 60

while #_G.plrs > 1 do
  display("Two or more players need to be in the game.", 1)
  wait()
end
display("Picking a map...", 3) pickMap()
teleport(0, 500, 0)

for i=0, roundTime do
  for i, v in pairs(currentPlayers) do
    if v.Character.Humanoid.Health <= 0 then
      table.remove(currentPlayers, v)
    end
  end
  wait(1)
end
print("Round over")

然而,这是错误的代码。 (每当你编写代码时,让其中带有“wait”函数的循环用于指示某些内容正在被错误地完成。)你应该使用Roblox的Events来处理游戏的逻辑。

  • 检查游戏是否应该仅在玩家数量发生变化时启动。
  • 仅在人形生物的健康状况发生变化时才会“寻找胜利者”(HealthChanged事件)。
  • 以某种计时器或间隔运行计时器(不要忘记,一旦有人赢了,你可能想要提早结束你的游戏)。

事件在繁忙的循环中具有许多优势;最明显的一点就是你的检查发生 他们正在检查的事情发生时,而不是以后。

答案 1 :(得分:3)

我建议你按照斯图尔特的建议来使用事件;这主要是为了提供有关协程正确使用它们的其他信息。

将coroutines视为可以返回值的函数,但有一个扭曲:当一个“普通”函数执行return时完成,当你从一个协程yield时,它会保存它的状态,这样resume就可以从你屈服的地方继续,好像什么都没发生一样。请注意,您只有{/ 1}} 来自一个协程,并且只到该协程yield的位置(这与调用函数并从中返回没有什么不同;控件返回到您调用函数的位置。

除此之外,resumeresume调用允许您将值传递给协同程序并从协程返回(中间)值。有关如何使用此示例的详细信息,请参阅此SO answer

一个人仍然可以从一个协程yield,它与从函数返回没有什么不同,这完成了它的执行。如果你当时检查协同程序的状态(return),它应该是“死的”。

所以,回答你的问题如何结束一个循环协程:你可以coroutine.status从它,你可以return从它(而不再yield()再次),或者你可以调用resume,然后您可以在error()调用的结果中捕获并检查。话虽如此,我同意斯图尔特的说法,这可能是解决问题的错误方法。