RunLater

We’ll explore the usage and important considerations for the frequently used RunLater method in Funkland.

Use RunLater


The RunLater function is used to control the execution order sequentially. Below is an example code snippet.

-- Print "Hello, World" after 2 seconds
Client.RunLater(function()
 print("Hello, World") 
end, 2)

As shown above, after n seconds, the anonymous function passed as the first parameter will be executed. By using this, you can easily control desired operations after a certain amount of time has passed.

Time Interval Guarantee Issue


Because the RunLater function executes a function after a certain period of time has passed, it isn’t influenced by the game’s frame rate. Therefore, it does not guarantee an exact time interval. Consider the following example:

-- 1초마다 메시지 출력
local startTime = os.time()

local function printMessage()
    local currentTime = os.time()
    local elapsedTime = currentTime - startTime
    print("Elapsed time: " .. elapsedTime .. "second")
end

local function runLaterExample()
    Client.RunLater(function()
        printMessage()
        runLaterExample()
    end, 1)
end

runLaterExample()

In the example above, we use RunLater to repeatedly execute a function that prints the elapsed time every second. However, since RunLater does not guarantee an exact time interval, the actual elapsed time may be slightly longer than one second.

Performance Issues


Because RunLater runs on the game’s main thread, executing long-running tasks can affect the game’s performance. If you need to perform time-consuming operations using RunLater, you may need to implement additional handling.

-- Execute a long-running task after 5 seconds
Client.RunLater(5, function()
    -- Long-running task
    for i = 1, 1000000000 do
        -- Perform the task
    end
end)

In the example above, we’ve scheduled a long-running task to be executed after 5 seconds. Because this task takes a very long time, it can negatively impact the game’s performance.

In the following example, we’ll look at a scenario where the long-running task is divided into multiple steps. Each step is performed over a short period of time, and then proceeds to the next step.

local totalIterations = 1000000000
local iterationsPerFrame = 1000000
local currentIteration = 0

local function performWork()
    for i = 1, iterationsPerFrame do
        -- Perform work
        currentIteration = currentIteration + 1
        if currentIteration >= totalIterations then
            -- Work complete
            print("Work complete.")
            return
        end
    end

    -- Continue work in the next frame
    Client.RunLater(performWork, 0)
end

-- Start work in the first frame
performWork()

Lua scripts do not inherently provide multi-threading capabilities, you must use alternative methods to handle long-running tasks.

In the example above, the long-running task is divided into increments of one million operations at a time. Each frame processes one million operations, and if the task isn’t finished, it continues in the next frame.

Validity Guarantee Issue


A RunLater that executes after n seconds cannot guarantee the validity of its actions following the wait. For example, the object you’re trying to access might have been destroyed by the time those n seconds have passed.

local text = Text()
Client.RunLater(function()
    text.text = "Hello, World"
end, 2)

text = nil
print(text.text)

In the example above, the script attempts to access the properties of a Text object after 2 seconds. However, if the Text object has been destroyed within those 2 seconds, an error may occur. Therefore, it’s advisable to perform a validity check before accessing the object inside RunLater.

local text = Text()
Client.RunLater(function()
    if text ~= nil then
        text.text = "Hello, World"
    end
end, 2)

As shown above, it’s a good idea to perform a validity check to guard against cases where the RunLater function executes after the object has been destroyed. By using this approach, you can ensure the validity even if the object is no longer available.

Last updated