5

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

2 回答 2

4

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

协程实际上只是一种使函数可以暂停自己的执行(使用coroutine.yield)的方法,该函数可以从外部恢复(使用coroutine.resume)。没有“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 的事件来处理您的游戏逻辑。

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

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

于 2014-02-18T20:11:32.533 回答
3

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

将协程视为可能返回值的函数,但有一个转折:虽然“正常”函数在执行时完成return,但当您yield从协程中完成时,它会保存其状态,这样就resume可以从您产生的点继续,就好像没啥事儿。请注意,您仅从yield 程开始,并且仅到达该resume协程完成的点(这与调用函数并从中返回没有什么不同;控制返回到您调用函数的点)。

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

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

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

于 2014-02-18T21:36:13.000 回答