Jacques
Jacques

Reputation: 75

Love2d. States system won't load the game state a second time

I'm just learning lua and love2d and I am trying to make an example game to get familiar. I'm following goature's tutorial on youtube and am using his states system to navigate the game. I finished writing the example code for the menu and decided I would like to be able to get back to the menu from the game. The problem is that the game will not load the game state a second time and instead gives me a gray screen. This should be the relavant code.

From the root file main.lua

function clearLoveCallbacks()
    love.draw = nil
    love.joystickpressed = nil
    love.joystickreleased = nil
    love.keypressed = nil
    love.keyrelease = nil
    love.load = nil
    love.mousepressed = nil
    love.mousereleased = nil
    love.update = nil
end

states = {}
function loadState(name)
    states = {}
    clearLoveCallbacks()
    local path = "states/" .. name
    require(path .. "/main")
    load()
end

function load()
end

function love.load()
    loadState("menu")

end

From the menu main.lua

function load()

    love.graphics.setBackgroundColor(190, 190, 190, 255)

    imgPlay = love.graphics.newImage("Textures/start.png")
    imgPlayOn = love.graphics.newImage("Textures/start_on.png")
    imgexit = love.graphics.newImage("Textures/exit.png")
    imgexitOn = love.graphics.newImage("Textures/exit_on.png")

    buttons = {
              {imgOff = imgPlay, imgOn = imgPlayOn, x = 400, y = 300 - 64, w = 256, h = 64, action = "play"},
              {imgOff = imgexit, imgOn = imgexitOn, x = 400, y = 300 + 64, w = 256, h = 64, action ="exit"}
              }
end
function love.mousepressed(x, y, button)
    if button == 1 then
        for k,v in pairs(buttons) do
            local ins = insideBox(x, y, v.x - (v.w/2), v.y - (v.h/2), v.w, v.h) -- must use v. for the rest of the arguments except the first 2 because that x and y defined in arguments of the function

            if ins then
                if v.action == "play" then
                    loadState("New_Game") -- loads new game for some reason if i load the menu state from game it won't load the game a secound time
                elseif v.action == "exit" then
                    love.event.quit() -- love2d function to quit
                end
            end
        end
    end
end

And from the New_Game main.lua

function load()
    require("States/New_Game/entities")
    love.graphics.setBackgroundColor(255,255,255,255)
    ents.startup()
    --local newEnt= ents.Create("new_ent", 128, 128)
    ents.Create("enemy_base", -math.random(128, 256), 128)
end
function love.keypressed(key, unicode)
    if love.keyboard.isDown("escape") then
        loadState("Menu")
    end
end

Upvotes: 0

Views: 523

Answers (1)

Nicol Bolas
Nicol Bolas

Reputation: 473926

The code you have provided, as written, cannot do what you seem to want.

You seem to want to be able to call loadState, and you want this function to load things into globals that effectively sets up a new "state".

Well, that might be fine... except that you are using require to do the loading. And, unless Love2D changed how the function works, require will only ever load a particular script once.

See, it is the execution of the script itself that is changing the state. It's defining a global load function, which you call. It defines some other functions in the love table. And so forth.

But this will only happen when the script is loaded and executed. And as previously said, require will only do this the first time you require a new module.

Presumably, what you want is dofile, not require. But honestly, I'd suggest re-architecting your system to not rely on globals. Register which states you want up-front, but don't have them set global values. Instead, have each state define a table that contains its load function. And the load function should register its Love2D callbacks.

Your "states" would look more like this:

local ret = {}

--Executed only once.
local imgPlay = love.graphics.newImage("Textures/start.png")
local imgPlayOn = love.graphics.newImage("Textures/start_on.png")
local imgexit = love.graphics.newImage("Textures/exit.png")
local imgexitOn = love.graphics.newImage("Textures/exit_on.png")

local buttons =
{
    {imgOff = imgPlay, imgOn = imgPlayOn, x = 400, y = 300 - 64, w = 256, h = 64, action = "play"},
    {imgOff = imgexit, imgOn = imgexitOn, x = 400, y = 300 + 64, w = 256, h = 64, action ="exit"}
}

local function mousepressed(x, y, button)
    if button == 1 then
        for k,v in pairs(buttons) do
            local ins = insideBox(x, y, v.x - (v.w/2), v.y - (v.h/2), v.w, v.h) -- must use v. for the rest of the arguments except the first 2 because that x and y defined in arguments of the function

            if ins then
                if v.action == "play" then
                    loadState("New_Game") -- loads new game for some reason if i load the menu state from game it won't load the game a secound time
                elseif v.action == "exit" then
                    love.event.quit() -- love2d function to quit
                end
            end
        end
    end
end

function ret.load()
    --Actual state setup.
    love.mousepressed = mousepressed

    love.graphics.setBackgroundColor(190, 190, 190, 255)
end

return ret

Your loadState function also needs to change:

function loadState(name)
    states = {}
    clearLoveCallbacks()
    local path = "states/" .. name
    local state = require(path .. "/main")
    state.load()
end

Oh, and I would advise you to ditch whatever tutorial you are "learning" from. It's teaching you terrible things. It involves way too much global usage, which is what led to this problem. If you're just learning Lua, then you are learning to use Lua very badly.

Upvotes: 1

Related Questions