Skip to content

Freezing

KINGTUT10101 edited this page Aug 22, 2024 · 4 revisions

Overview:

The freezing system gives you more control over when the stack can change. When it's active, this system will redirect stack changes into a buffer until it is unfrozen, after which it will copy the changes back into the original stack.

This is used automatically within sceneMan:event to prevent errors when scenes make changes to the stack. Without it, a scene might remove another scene from the stack and cause Scene Man to iterate over the wrong value or crash the entire system. Instead, stack changes only apply AFTER the event trigger has finished.

It is recommended that you manually trigger the freezing system in your game as shown below. This will prevent any stack changes until the next update cycle. This will be explained more in the following example.

--- main.lua

function love.update (dt)
    sceneMan:freeze ()
    sceneMan:event ("update", dt)
end

function love.draw ()
    sceneMan:event ("draw")
    sceneMan:unfreeze ()
end

Example:

Let's reuse the original example from the wiki. In this case, let's push the menu scene inside the game scene rather than inside love.load. You may encounter situations like this if you use immediate-mode GUI libraries like SUIT, where a player might push a button to transition into another scene.

--- main.lua

local sceneMan = require ("sceneMan")

function love.load ()
    local initialRectW = 300

    sceneMan:newScene ("game", require ("gameScene"), initialRectW)
    sceneMan:newScene ("menu", require ("menuScene"))

    -- Notice how we aren't pushing the menu scene here anymore?
    sceneMan:push ("game")

end

function love.update (dt)
    sceneMan:event ("update", dt)
end

function love.draw ()
    local rng = math.random ()

    sceneMan:event ("draw", rng)
end
--- gameScene.lua

-- (SNIPPET)

function thisScene:update (dt)
    -- Now we are pushing the menu scene onto the stack inside the game scene
    if yes ~= true then
        sceneMan:push ("menu")
        yes = true
    end
end

Everything still works, right? What's the big deal? Well, let's modify the menu scene a bit to find out. Let's imagine that the menu scene now prints a test value that gets initialized inside the update event callback as shown below:

--- menuScene.lua

-- (SNIPPET)

local test

function thisScene:update (dt)
    dt = dt
    
    -- This is where our value gets its initial value, for demonstration purposes
    if test == nil then
        test = 24
    end
end

function thisScene:draw (rng)
    -- Renders some GUI items
    love.graphics.setColor (1, 1, 1, 1)
    love.graphics.print ("Hello world! This is a GUI!", 400, 400)
    love.graphics.print ("Delta Time: " .. dt, 400, 425)
    love.graphics.print ("RNG: " .. sceneMan.shared.rngValue, 400, 450)
	
    -- But what happens when we try to perform math on this value???
    test = test + 1
    love.graphics.print ("Test: " .. test, 400, 475)
end

Now you'll probably be looking at a nasty error, right? Why is that? Well, when we pushed the menu scene onto the stack inside the update callback (within the game scene), the menu scene didn't get a chance to execute its update callback function. This means that the test value was never initialized, and it was nil when we tried to add to it within the draw callback function.

Thankfully, this is an easy fix! If we freeze the stack before the update event and unfreeze it after the draw event, the stack changes will only apply after the drawing event is finished. This ensures that the menu scene isn't actually added onto the stack until the next update trigger is called. Just modify your code like what's shown below:

--- main.lua

local sceneMan = require ("sceneMan")

function love.load ()
    local initialRectW = 300

    sceneMan:newScene ("game", require ("gameScene"), initialRectW)
    sceneMan:newScene ("menu", require ("menuScene"))

    sceneMan:push ("game")

end

function love.update (dt)
    sceneMan:freeze () -- This will temporarily prevent stack changes while we trigger the events
    sceneMan:event ("update", dt)
end

function love.draw ()
    local rng = math.random ()
    
    sceneMan:event ("draw", rng)
    sceneMan:unfreeze () -- Now the stack changes can be applied!
end

Hooray! Looks like the program is working once again!

image

Clone this wiki locally