Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to end a looping coroutine in Lua?

Tags:

lua

roblox

I'm currently working on a game using Roblox (which uses Lua). It is a basically made up of several minigames. At the beginning of each round, all the players in game are put in a table and teleported to an area. That is where the coroutine comes into play. As the round is in progress, I want a coroutine to start. Every second that coroutine checks if the player's health is below zero, and removes them from the currentPlayer table if it is.

Sorry if I am not describing the problem correctly, but the coroutine will not yield. I haven't used coroutines before, so I am probably trying to yield it the wrong way. I know most of you will not be familiar with Roblox, but the Lua syntax is the same.

Can someone please give me an example of how I would end a looping coroutine?

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
like image 549
user3314993 Avatar asked Feb 18 '14 19:02

user3314993


1 Answers

Lua is a single-threaded language. Coroutines do not cause functions to execute in parallel.

Coroutines are effectively just a way to make a function that can pause its own execution (using coroutine.yield), that can be resumed from outside (using coroutine.resume). There is no "coroutine.running": there's only one line "running" at any given time.

If Roblox were meant for you to use wait() to jump out of the Lua thread, you would write this as a series of loops that check their condition and then call 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")

However, this is bad code. (Whenever you write code, let loops with a "wait" function in them serve to indicate that something is being done incorrectly.) You should be using Roblox's Events to handle your game's logic.

  • Check to see if the game should start only when the number of players changes.
  • "Look For Winners" only when a Humanoid's health changes (the HealthChanged event).
  • Run the timer on some kind of timer or interval (don't forget that you'll probably want to end your game early once somebody has won).

Events have many, many advantages over a busy loop; the most visible one will be that your checks occur when the thing they're checking for happens, and not later.

like image 55
Stuart P. Bentley Avatar answered Nov 15 '22 07:11

Stuart P. Bentley