Page 1 of 1

States for menus and such

Posted: Fri Apr 15, 2016 3:34 pm
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 341 times

Re: States for menus and such

Posted: Sat Apr 16, 2016 3:24 pm
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?

Re: States for menus and such

Posted: Sat Apr 16, 2016 4:27 pm
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.

Re: States for menus and such

Posted: Sat Apr 16, 2016 5:40 pm
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.

Re: States for menus and such

Posted: Sat Apr 16, 2016 11:43 pm
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.