stateful.lua
- kikito
- Inner party member
- Posts: 3153
- Joined: Sat Oct 03, 2009 5:22 pm
- Location: Madrid, Spain
- Contact:
Re: stateful.lua
Thanks. I will not be able to check it today, but I will try to do it tomorrow.
When I write def I mean function.
- JaquesEdrillavo
- Prole
- Posts: 7
- Joined: Tue Apr 08, 2014 2:12 am
- Location: Mexico
Re: stateful.lua
Hey!Then Game can be defined as a class inside Game.lua, and have a Menu state, a Play state, and so on.
Here's how you would create a Game with a Menu state:
That's the basic structure. You could add another state called "Play" similar to "Menu" following this schema.Code: Select all
-- game.lua Game = class("Game"):include(Stateful) function Game:initialize() self.image = love.graphics.newImage("image.jpg") self:gotoState("Menu") -- start on the Menu state end local Menu = Game:addState("Menu") function Menu:enteredState() -- create buttons, options, etc and store them into self print("entering the state menu") end function Menu:draw() -- draw the menu end function Menu:update(dt) -- update anything that needs updates end function Menu:exitedState() -- destroy buttons, options etc here print("exiting the menu state") end
That's pretty much it. Let me know if you have any questions.
Awesome work. Really!
Im kind of new with Löve, im struggling like you have no idea.
I've been having some issue with trying to define the Game = class("Game"):include(Stateful)
I leave it Global, but still says that class is a nil value.
I even copied exactly as you did in your explanation and still got the same error.
Do you have an idea of what I could be doing wrong?
Thank you for everything!
- Positive07
- Party member
- Posts: 1014
- Joined: Sun Aug 12, 2012 4:34 pm
- Location: Argentina
Re: stateful.lua
for i, person in ipairs(everybody) do
[tab]if not person.obey then person:setObey(true) end
end
love.system.openURL(github.com/pablomayobre)
[tab]if not person.obey then person:setObey(true) end
end
love.system.openURL(github.com/pablomayobre)
- kikito
- Inner party member
- Posts: 3153
- Joined: Sat Oct 03, 2009 5:22 pm
- Location: Madrid, Spain
- Contact:
Re: stateful.lua
Hi there! It took me a while to get some time to test this, with Ludum Dare and Real Life getting in the way.enygmata wrote:I attached one simple love file for testing purposes. To make the problem happen, open the menu.lua file and save it again. Lurker will reload the file and an assertion error will be thrown:kikito wrote:Does any of you guys have a sample *.love file showing the issue?State Menu already exists on class Game
First of all: there was an error in main.lua:15 - it referenced 'self' instead of 'game', and this raised an error. I fixed that, and will be ignoring it for the rest of this post.
Second, the solution you posted (removing the assertion in stateful.lua) is not really solving the issue, it's masking it temporarily. You are leaving the "old state" there instead of removing it. Which has lots of unintended consequences. For example, if you remove one function from a state and the state is reloaded by lurker, the function will "still be there" when lurker reloads. It will still "mask" parent functions, even if its code doesn't exist any more. It's one of those ninja-bugs that you really don't want to have in your code. So I am not going to recommend it.
Third, not everything is lost! I found a way to make things work. It's not as pretty as I'd like, but it's something. The gist is this: you can use stateful with lurker, as long as all the states affecting one class stay in the same file as the class.
In other words, If you move the content of menu.lua to the end of game.lua and removed the `require "menu"` from main.lua, it works - you can start the game, change the menu state message to "Menu State 2", for example, and it refreshes correctly.
The reasons for this are complex. Lurker is a "file-based" thing. game.lua and menu.lua, are two files acting on the same piece of memory. So lurker gets confused - it loads menu again, but not game.lua. But if you put everything in one file, Lurker can work with it.
There might be other ways around this - some of them might need help from Lurker's author. But putting everything in one file is the simplest solution. Here's the fixed stateful-lurker.love:
Finally, I noticed that you rely on global variables to do almost everything; you define classes as globals:
Code: Select all
Game = class('Game')
...
Code: Select all
class = require "middleclass"
lurker = require "lurker"
...
- Require the libraries you need on each file where you need them, as local variables
- Define classes as locals and return them at the end of the files where they are defined
Code: Select all
local class = require 'class'
local Game = class('Game')
... -- (Define Game and Menu)
return Game
Code: Select all
local lurker = require 'lurker'
local Game = require 'Game'
local game
function love.load()
game = Game:new()
end
...
Here's a version of stateful-lurker with all the globals removed:
I hope this helps.
Last edited by kikito on Thu May 01, 2014 10:30 am, edited 1 time in total.
When I write def I mean function.
- kikito
- Inner party member
- Posts: 3153
- Joined: Sat Oct 03, 2009 5:22 pm
- Location: Madrid, Spain
- Contact:
Re: stateful.lua
(sorry about double posting, I'm answering to two different posts here)
at the beginning of game.lua.
In general, use local xxx = require 'xxx' on all the files that need to use xxx. It's a bit longer to write, but it pays off. The end of my previous post explains a bit more about this.
I recommend doing this instead:
Code: Select all
local class = require 'middleclass'
local Stateful = require 'stateful'
In general, use local xxx = require 'xxx' on all the files that need to use xxx. It's a bit longer to write, but it pays off. The end of my previous post explains a bit more about this.
When I write def I mean function.
- Positive07
- Party member
- Posts: 1014
- Joined: Sun Aug 12, 2012 4:34 pm
- Location: Argentina
Re: stateful.lua
Yeah sure! but I think that this is not done here or here, making things confusing. It would be great if you changed:kikito wrote: I recommend doing this instead:
require "middleclass" to local class = require "middleclass"
for i, person in ipairs(everybody) do
[tab]if not person.obey then person:setObey(true) end
end
love.system.openURL(github.com/pablomayobre)
[tab]if not person.obey then person:setObey(true) end
end
love.system.openURL(github.com/pablomayobre)
- kikito
- Inner party member
- Posts: 3153
- Joined: Sat Oct 03, 2009 5:22 pm
- Location: Madrid, Spain
- Contact:
Re: stateful.lua
You are right, of course. I've updated those, thanks!
When I write def I mean function.
- CaptainMaelstrom
- Party member
- Posts: 161
- Joined: Sat Jan 05, 2013 10:38 pm
Re: stateful.lua
Hey kikito. I've been playing around with stateful lately and I really like it.
I do have a couple suggestions though. I ran some tests and noticed that you can enter states without leaving them, at least, the "enteredState" function executes for a specific state if you try to "gotoState" into it without having left it first. Example:
Running that code and pressing 'f' twice yields a string '133'. Is this intended?
A bigger problem for me is that
adding that code and switching to the nil state doesn't add '2' to the string. Is there anyway to get a callback function to trigger when a troop instance goes to the nil state?
I do have a couple suggestions though. I ran some tests and noticed that you can enter states without leaving them, at least, the "enteredState" function executes for a specific state if you try to "gotoState" into it without having left it first. Example:
Code: Select all
function Troop:initialize() end
function Visible:enteredState() str = str .. '3' end
function love.load()
troop = Troop()
str = '1'
end
function love.draw() lg.print(str,20,20) end
function love.keypressed(key)
if key=='f' then troop:gotoState('Visible') end
if key=='a' then troop:gotoState(nil) end
end
A bigger problem for me is that
Code: Select all
function Troop:enteredState() str = str .. '2' end
Re: stateful.lua
A bit of a slow response, but just wanted to clarify on this point: Unless you meant this was due to the combination of Lurker and Stateful, Lurker should work quite happily with modules which are set to global variables. I wrote it in a way such that it rebuilds all the corresponding module tables in place when it reloads a module, rather than recreating the module. This was so that things like metatables are also immediately effected without objects needing to be reconstructed, and is also the reason for another point you mentioned:kikito wrote:That will give you trouble later on, especially if you want to use it with a dynamic loader such as lurker
I won't go into too much detail, but many of the decisions were made to try and make lurker work really well for quick, small, iterative changes -- for example, if you want to perfectly tweak the gravity in a game and see the effects of this immediately. Due to how it works it does mean you either need to explicitly set a table's deleted function to nil or simply restart the game for changes where you delete a function.kikito wrote: if you remove one function from a state and the state is reloaded by lurker, the function will "still be there" when lurker reloads.
- kikito
- Inner party member
- Posts: 3153
- Joined: Sat Oct 03, 2009 5:22 pm
- Location: Madrid, Spain
- Contact:
Re: stateful.lua
Yes - reason below.CaptainMaelstrom wrote: Running that code and pressing 'f' twice yields a string '133'. Is this intended?
'nil' is not a state. In consequence, it does not have entered/exited callbacks, nor it does occupy a place in the internal state stack.CaptainMaelstrom wrote: A bigger problem for me is that
adding that code and switching to the nil state doesn't add '2' to the string. Is there anyway to get a callback function to trigger when a troop instance goes to the nil state?Code: Select all
function Troop:enteredState() str = str .. '2' end
If you want your objects to always be in a state, you have to provide one for them - call it Default or Init or Idle or something. You can probably make your instances go to that state by default in their constructor:
Code: Select all
function Troop:initialize()
self:gotoState('Default')
end
function Default:enteredState()
str = str .. '1'
end
Thank you for your clarifications.rxi wrote:...
When I write def I mean function.
Who is online
Users browsing this forum: Bing [Bot], Google [Bot] and 3 guests