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

Posted

技术标签:

【中文标题】如何在 Lua 中结束循环协程?【英文标题】:How to end a looping coroutine in Lua? 【发布时间】:2014-03-18 18:51:21 【问题描述】:

我目前正在使用 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

【问题讨论】:

感谢您修复代码,我没有正确发布它。 【参考方案1】:

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")

但是,这是错误的代码。 (每当您编写代码时,让其中带有“等待”函数的循环用于指示某些操作不正确。)您应该使用 Roblox 的 Events 来处理您的游戏逻辑。

检查游戏是否应该仅在玩家数量发生变化时才开始。 仅当人形机器人的健康状况发生变化(HealthChanged 事件)时“寻找赢家”。 以某种计时器或间隔运行计时器(不要忘记,一旦有人获胜,您可能希望提前结束游戏)。

与繁忙的循环相比,事件有很多很多优点;最明显的是您的检查发生在他们正在检查的事情发生时,而不是稍后。

【讨论】:

【参考方案2】:

我建议你按照 Stuart 的建议来使用事件;这主要是为了提供有关协程的附加信息,以帮助您正确使用它们。

将协程视为可以返回值的函数,但有一点不同:虽然“正常”函数在执行 return 时完成,但当您从协程中 yield 时,它会保存其状态,以便 @987654324 @ 然后可以从您屈服的点继续,就好像什么都没发生一样。请注意,您仅yield 来自 一个协程,并且仅到达该协程的resume 完成的点(这与调用函数并从它返回没有什么不同;控制返回到调用函数的位置)。

除此之外,resumeyield 调用允许您将值传递给协程并从协程返回(中间)值。请参阅SO answer 了解如何使用它的示例。

仍然可以从协程中return,这与从完成执行的函数返回没有什么不同。如果查看当时协程的状态(coroutine.status),应该是“死”了。

所以,要回答你的问题,如何结束循环协程:你可以从它return,你可以从它yield()(永远不要再resume它),或者你可以调用error(),然后您可以在resume 调用的结果中捕获并检查它。话虽如此,我同意 Stuart 的观点,即这可能是解决您问题的错误方法。

【讨论】:

以上是关于如何在 Lua 中结束循环协程?的主要内容,如果未能解决你的问题,请参考以下文章

在循环中使用协程

lua协程实现

[xlua]探索笔记之协程

如何将协程添加到正在运行的 asyncio 循环中?

如何给nginx的server

lua脚本延迟10秒怎么写