States for menus and such

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
Teshi
Prole
Posts: 11
Joined: Mon Feb 01, 2016 6:51 pm

States for menus and such

Post by Teshi »

Hi i'm using goature's states tutorial to base a states system for my game and it works as in i can go from the menu into the game. But when i try to loadState back into the menu i just get a blank screen.

What im wondering is if someone could explain his states main.lua file in his video so that I can try and pinpoint why its not drawing any of the screen.

Controls
- wasd to move
-mouse and left click to aim and shoot
- esc to go back to menu (just for testing)

https://www.youtube.com/watch?v=L_OrFXyorwI -- video in question.
courseworkProject.love
(29.35 KiB) Downloaded 340 times
Teshi
Prole
Posts: 11
Joined: Mon Feb 01, 2016 6:51 pm

Re: States for menus and such

Post by Teshi »

Could anyone help please? Im using his states file to go into my game, then when i try to go back to the menu its just a black screen and I dont know how to fix it. Could anyone help?
bobbyjones
Party member
Posts: 730
Joined: Sat Apr 26, 2014 7:46 pm

Re: States for menus and such

Post by bobbyjones »

I did not look at your code but make sure that you load the States when switching. You may destroy a state when leaving it so when you return it's empty you get just a blank screen. So make sure you reload the state so that you would return to something.
User avatar
s-ol
Party member
Posts: 1077
Joined: Mon Sep 15, 2014 7:41 pm
Location: Cologne, Germany
Contact:

Re: States for menus and such

Post by s-ol »

The reason is that when you call require multiple times it only runs the file once (the first time) and just uses the cached result after that.

As a result all your function love.update(dt), love.draw() declarations etc are only done the first time, and when you try to loadState() back into the menu you clear the callbacks but require()-ing menu again doesn't actually do anything.

I propose two solutions:
1.) a cheap way of making it work with minimal changes:
wrap every complete state file in a single function and return it from the module. For example:

Code: Select all

return function ()
function load()
  love.graphics.clear()
  require "scripts"
  love.graphics.setBackgroundColor(60, 60, 60, 255 )
  
  play = love.graphics.newImage("assets/play.png")
....

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 )
			
			if ins then
				if v.action == "play" then
					loadState("Level1")
				elseif v.action == "exit" then
					love.event.quit()
				end
			end
		end
	end
end
end
and then slightly change loadState():

Code: Select all

state = {}
function loadState(name)
  states = {}
	clearLoveCallbacks()
	local path = "states/" .. name
	require(path .. "/main")() -- TWO EXTRA PARENTHESIS - CALL THE FUNCTION THE MODULE RETURNS
	load()
end
Also instead of making a global load() which is pretty ugly you can use the function the module returns to do that.

however I would advise you start using a "table based" state concept, because it is more flexible, easier to debug and doesn't rely on all the globals which can easily sneak in hard to find bugs:

- make each gamestate module return a table
- the table contains all the callbacks like .update, .draw etc.
- to load a state just require that module and assign the table to a global variable (current_state)
- love.update, love.draw etc call current_state.update, current_state.draw etc.
- add a .load to the table that resets the state every time instead of relying on the default values so the game restarts when you switch back to it from the menu a second time

for example:

Code: Select all

state = {}
function loadState(name)
  local module = "states." .. name
  state = require(module)
  state.load()
end

function love.draw(...)
  if state.draw then state.draw(...) end
end

function love.update(...)
  if state.update then state.update(...) end -- only call if it exists
end

function love.keypressed(...)
  if state.keypressed then state.keypressed(...) end -- only call if it exists
end
-- etc.
and the file states/menu/init.lua:

Code: Select all

local Menu = {}
local buttons

function Menu.load()
  buttons = ... -- reset buttons
end

function Menu.draw()
  -- draw buttons etc.
end

return Menu
Note that everything is local, there is no reason to make "Menu" or "buttons" global.

also a few other unrelated notes:
- with require() do not use slashes, use dots (states.Menu.main)
- if you name your states/Menu/main.lua as init.lua instead, you can require("states/Menu") (like in my code example above); if the given module is a directory it will automatically try /init.lua and you can still have each as it's own folder.

s-ol.nu /blog  -  p.s-ol.be /st8.lua  -  g.s-ol.be /gtglg /curcur

Code: Select all

print( type(love) )
if false then
  baby:hurt(me)
end
Teshi
Prole
Posts: 11
Joined: Mon Feb 01, 2016 6:51 pm

Re: States for menus and such

Post by Teshi »

Thank you A LOT! Im still quite new to lua and love (and i guess programming in general) so thank you for your help and explaining whats going on. I will try to implement a better states system when I have the time.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Google [Bot] and 7 guests