How to LÖVE - Now with text-based tutorials

General discussion about LÖVE, Lua, game development, puns, and unicorns.
User avatar
Positive07
Party member
Posts: 1014
Joined: Sun Aug 12, 2012 4:34 pm
Location: Argentina

Re: How to LÖVE - A LÖVE tutorial series

Post by Positive07 »

s-ol wrote:
Robin wrote:
MadByte wrote:Basically thats what I do for every module, but why should I add an extra line "local Object=require("class")" to every single class, for every single required module I create. I don't see the mysterious big advantage when doing everything local. All my main.lua files look like this:
Sorry to bring the globals thing up again, but IMO that's like saying "The warning lights kept flashing. I thought that was annoying so I turned them off. I don't see the mysterious big advantage for using warning lights."
He emphasized "everything", I totally agree with him. IMO blindly following the "no globals" rule is just as bad as not thinking about scope at all. If he literally uses that throughout all his files, it would be foolish not to have it global.
Think about it this way, Object is global and is how I create new classes, I use it in most of my files... now I stop using this code, a couple of months or maybe someone else comes and wants to use it, I/or this person grab one of the files, say tile.lua and put it in another project. Now since I checked all the required files at the top, I know that it requires map.lua and collision.lua and that is it, so I grab this three files and put it in my project, but it still doesn't work it gives me an error about the Object variable which I have no idea what it is or where it comes from, I look at other files but there is no object.lua and no other file is exporting such a table... Of course if I new that it is a global variable which is actually the table defined in the class.lua and is required at the top of main.lua I could easily find it, but since I didn't know I had to lose my time searching... You can't assume that everyone will be able to guess what global variables are required and where they actually come from, even less in a tutorial.
for i, person in ipairs(everybody) do
[tab]if not person.obey then person:setObey(true) end
end
love.system.openURL(github.com/pablomayobre)
User avatar
s-ol
Party member
Posts: 1077
Joined: Mon Sep 15, 2014 7:41 pm
Location: Cologne, Germany
Contact:

Re: How to LÖVE - A LÖVE tutorial series

Post by s-ol »

Positive07 wrote:
s-ol wrote:
Robin wrote: Sorry to bring the globals thing up again, but IMO that's like saying "The warning lights kept flashing. I thought that was annoying so I turned them off. I don't see the mysterious big advantage for using warning lights."
He emphasized "everything", I totally agree with him. IMO blindly following the "no globals" rule is just as bad as not thinking about scope at all. If he literally uses that throughout all his files, it would be foolish not to have it global.
Think about it this way, Object is global and is how I create new classes, I use it in most of my files... now I stop using this code, a couple of months or maybe someone else comes and wants to use it, I/or this person grab one of the files, say tile.lua and put it in another project. Now since I checked all the required files at the top, I know that it requires map.lua and collision.lua and that is it, so I grab this three files and put it in my project, but it still doesn't work it gives me an error about the Object variable which I have no idea what it is or where it comes from, I look at other files but there is no object.lua and no other file is exporting such a table... Of course if I new that it is a global variable which is actually the table defined in the class.lua and is required at the top of main.lua I could easily find it, but since I didn't know I had to lose my time searching... You can't assume that everyone will be able to guess what global variables are required and where they actually come from, even less in a tutorial.
Well, not all of my code is to be taken apart and used in bits or even to be used publicly. If it were then it would be packaged in an (usually instantiable) module that has no dependencies like that.

Also in my code I only ever define globals in main.lua or at least globals are only ever used downwards from where they are defined with an initial value in the require chain. I also export module return values as globals in the main file instead of in the module if they are needed outside.
In moonscript global assignments are also explicit so it is very obvious what a file exports at a glimpse.

Lastly i think you're overestimating what i mean by 'some' globals are fine. Usually there is like four in a standard game I would make, being the state manager, a map or world object and a width and height variable.

Oh and I bet you use globals a lot in your code actually - where do "love", "table" and "print" come from again? ;)

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
User avatar
zorg
Party member
Posts: 3468
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: How to LÖVE - Now with text-based tutorials

Post by zorg »

If I'd want to be cheeky, i'd say that love, table, print and their friends are also in a thread-local table, called _G. :3
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
User avatar
Positive07
Party member
Posts: 1014
Joined: Sun Aug 12, 2012 4:34 pm
Location: Argentina

Re: How to LÖVE - Now with text-based tutorials

Post by Positive07 »

table and print are part of the standard library of Lua, so they should be available everywhere, same with math, (io and os I don't really trust since they may be hidden by a sandbox for security reasons) LÖVE should be an stated dependency of the code, for example in this case you can see it in the name "How to LÖVE".

You can have a few globals but you should state somewhere that the code needs those globals and where and how are they defined... yes it may be repetitive but if someone wants to use your code as reference (as is the case with tutorials) then they may not look all over the place, if I see a file called tile.lua I can easily guess that this is the file where the code for handling tile maps is located... I may not even look at main or other file.

Assuming is most of the time a problem so you should be careful when doing it, most of the times is just because we want to be lazy or because we are not really thinking about a different possibility.

How hard can it be to write a comment at the top that says: "Depends on the global Object variable, which is defined in main.lua"?
Then again if you do that why not simply do local Object = require "class"? it's shorter
for i, person in ipairs(everybody) do
[tab]if not person.obey then person:setObey(true) end
end
love.system.openURL(github.com/pablomayobre)
User avatar
Karai17
Party member
Posts: 930
Joined: Sun Sep 02, 2012 10:46 pm

Re: How to LÖVE - Now with text-based tutorials

Post by Karai17 »

The way I see it, every lua file should be its own, independant scope, unless explicitly stated otherwise. There is no compelling reason to litter the global namespace. Doing so is just laziness. Each file being a self-contained unit that can then be required into another file as-needed without affecting that file or any other files is just simply smart. If you feel like something needs to be global, chances are you are mistaken and the code can be refactored to be container-friendly. I will note, there are a few exceptions to that rule:
  • Some object in LOVE need to maintain a single state over a whole game, such a a gamestate/scene object or an in-game console or other such debugging tools. These sorts of things either run your game, or run out of the scope of your game's main functionality and can be forgiven for being global.
  • Some shortcuts I've been known to take is to have any game options or language files set as a global table. These options are queried frequently and it would be a pain to load them out of a file every time you needed to apply volume levels to a sound file, for instance. I will note however that changing the game's options is only done in a single file (options menu) and not something that the user can update on the fly. These shortcuts are individual decisions weighing pros and cons of taking said short cuts which I think makes them more acceptable.
When I do end up needing to use a global, I use the naming convention of prepending it with _G and having the variable in all caps. This makes it very obvious (and is syntax highlighted) that the variable is global.

Code: Select all

_G.SCENE   = require "scene" -- backbone of the whole game engine!
_G.EVENTS  = require "talkback" -- explicit purpose is to facilitate cross-file talk
_G.CONSOLE = require "console" -- allows you to execute debug commands or raw lua from anywhere in the game
local json = require "dkjson" -- this module has no internal state to maintain so requiring it locally only in the files i need it in is best

_G.PREFERENCES = love.filesystem.load("preferences.json")()
_G.PREFERENCES = json.decode(_G.PREFERENCES) -- this table gets queried throughout most of my game so as a short cut, I load it globally instead of loading it from the hard drive every time I switch states
Noting that I use talkback that is able to facilitate event propogation across a whole project, I could even make things like scene and console local somewhere and have talkback work as a middle layer, but that's a whole lot of boilerplate for no real gain. it's better used for game events where your gameplay scene has a bunch of event listeners set up and then your other files can trigger those events as needed.
STI - An awesome Tiled library
LÖVE3D - A 3D library for LÖVE 0.10+

Dev Blog | GitHub | excessive ❤ moé
Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 4 guests