## Trying to Get Rid of Globals

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.
shatterblast
Party member
Posts: 136
Joined: Tue Dec 11, 2012 9:47 pm
Location: Dallas, Texas, USA

### Trying to Get Rid of Globals

I do not consider myself a professional coder, but I pass it by as a hobby. To my understanding, it is standard etiquette to avoid global declarations. To my limited knowledge, I have made some globals into locals.

I am also aware that my software needs work, but I'm not yet ready to focus on animation speeds and sound clips. I prefer to work on game states next.

Anyhow, I could use some input into how to convert some of the globals in love.load() into local declarations instead. Any suggestions will be highly appreciated. Thanks!

Code: Select all

local back_ground = love.graphics.newImage("background01.png")

--______________________________________________________________________

local spritesheet1 = love.graphics.newImage("sparkle_set01.png")
local spritesheet2 = love.graphics.newImage("sparkle_set02.png")
local spritesheet3 = love.graphics.newImage("sparkle_set03.png")

--______________________________________________________________________

local spritesheet4 = love.graphics.newImage("safir_test01.png")
local spritesheet5 = love.graphics.newImage("shell_burst_03.png")

--______________________________________________________________________

local animationState_Effects = "Effect_0"
local animationState_Saphir = "Effect_Saphir_1"
local soundState = "Sound_1"

local sound03 = love.audio.newSource("explosion03.ogg", "static")
local sound04 = love.audio.newSource("explosion04.ogg", "static")

require("anal")

spritesheet1:setFilter("nearest", "nearest")
animation1 = newAnimation(spritesheet1, 192, 192, 0.1, 110)
--______________________________________________________________________

spritesheet2:setFilter("nearest", "nearest")
animation2 = newAnimation(spritesheet2, 200, 200, 0.1, 80)
--______________________________________________________________________

spritesheet3:setFilter("nearest", "nearest")
animation3 = newAnimation(spritesheet3, 200, 200, 0.1, 80)
--______________________________________________________________________

spritesheet4:setFilter("nearest", "nearest")
--MAKE SURE THE LAST NUMBER IS THE NUMBER OF FRAMES!!!
animation4 = newAnimation(spritesheet4, 120, 203, 0.1, 60)

--______________________________________________________________________

spritesheet5:setFilter("nearest", "nearest")
--MAKE SURE THE LAST NUMBER IS THE NUMBER OF FRAMES!!!
animation5 = newAnimation(spritesheet5, 159, 203, 0.1, 31)

--______________________________________________________________________

--TO DO: Add more sound here.
--______________________________________________________________________

--Background music for battles.
local battle_music_shuffle = table.shuffle{'battle_music_Derek_Oldman_-_Notch.ogg', 'battle_music_Melodie_en_sous-sol_-_azul_ul_inu.ogg', 'battle_music_mindthings_-_Eve_.ogg', 'battle_music_Outsider_-_Dangerous_Groups.ogg', 'battle_music_Piter_-_Reveranger__amp__Piter_-_HYMNOMYNA__chillout_.ogg', 'battle_music_Tripple_T_-_The_Chill_Area.ogg', 'battle_music_Wade_-_Pozitivli_Tuned_Up.ogg', 'battle_music_WoNd3RBoY_-_WoNd3RBoY_-_MilkyWay__original_mix_.ogg'}

background_Music01 = love.audio.newSource(battle_music_shuffle[1])

background_Music01:setVolume(0.25)

--______________________________________________________________________
end

function table.shuffle(array)
local arrayCount = #array
for i = arrayCount, 2, -1 do
local j = love.math.random(1, i)
array[i], array[j] = array[j], array[i]
end
return array
end

function love.update(dt)
animation1:update(dt)
animation2:update(dt)
animation3:update(dt)
animation4:update(dt)
animation5:update(dt)

end

function love.draw()
love.graphics.draw(back_ground, 0, 0)

love.graphics.print("Press 1, 2, 3, or 4 to alternate between animations.", 50, 50)
love.graphics.print(animationState_Effects, 50, 110)

if animationState_Saphir == "Effect_Saphir_1" then
animation4:setMode("loop")
animation4:draw(600, 150)

elseif animationState_Saphir == "Effect_Saphir_2" then
animation5:setMode("once")
animation5:draw(580, 150)

if animation5:getCurrentFrame() == 31 then
animationState_Saphir = "Effect_Saphir_1"
animation4:reset()
animation4:play()

end
end

--______________________________________________________________________

if animationState_Effects == "Effect_1" then
animation1:setMode("once")
animation1:draw(250, 250)

if animation1:getCurrentFrame() == 110 then
animationState_Effects = "Effect_0"

end

elseif animationState_Effects == "Effect_2" then
animation2:setMode("once")
animation2:draw(250, 250)

if animation2:getCurrentFrame() == 80 then
animationState_Effects = "Effect_0"

end

elseif animationState_Effects == "Effect_3" then
animation3:setMode("once")
animation3:draw(250, 250)

if animation3:getCurrentFrame() == 80 then
animationState_Effects = "Effect_0"

end

elseif animationState_Effects == "Effect_4" then
animationState_Saphir = "Effect_Saphir_2"

end

if not background_Music01:isPlaying() then
stop_songs()

--The reason to call this stuff a second time is to re-shuffle the music.
battle_music_shuffle = table.shuffle{'battle_music_Derek_Oldman_-_Notch.ogg', 'battle_music_Melodie_en_sous-sol_-_azul_ul_inu.ogg', 'battle_music_mindthings_-_Eve_.ogg', 'battle_music_Outsider_-_Dangerous_Groups.ogg', 'battle_music_Piter_-_Reveranger__amp__Piter_-_HYMNOMYNA__chillout_.ogg', 'battle_music_Tripple_T_-_The_Chill_Area.ogg', 'battle_music_Wade_-_Pozitivli_Tuned_Up.ogg', 'battle_music_WoNd3RBoY_-_WoNd3RBoY_-_MilkyWay__original_mix_.ogg'}
background_Music01 = love.audio.newSource(battle_music_shuffle[1])

background_Music01:setVolume(0.25)
background_Music01:play()
end

end

function love.keypressed(key)
if key == "1" then
animationState_Effects = "Effect_1"
animation1:reset()
animation1:play()

elseif key == "2" then
animationState_Effects = "Effect_2"
animation2:reset()
animation2:play()
love.audio.play(sound03)

elseif key == "3" then
animationState_Effects = "Effect_3"
animation3:reset()
animation3:play()
love.audio.play(sound04)

elseif key == "4" then
animationState_Saphir = "Effect_Saphir_2"
animation5:reset()
animation5:play()

end
end

--Place more songs here as the list grows so that all background music ceases before starting a new one.
function stop_songs()
love.audio.stop(background_Music01)
end
Love file:
https://www.dropbox.com/s/cy5s7erwij76k ... de_21.love

micha
Inner party member
Posts: 1083
Joined: Wed Sep 26, 2012 5:13 pm

### Re: Trying to Get Rid of Globals

shatterblast wrote:To my understanding, it is standard etiquette to avoid global declarations.
While it is a good idea to reduce the number of global variable, don't forget that some data is used globally and then making it local will introduce a lot of extra work to access it from everywhere. So personally I try to follow this rule: Make those variables local, that act locally.

In your case you have the assets stored in global variables. In my opinion that makes sense, because you load them in love.load and access them in love.draw. How would you transfer this data, if not via globals?

Besides that, you can still tidy up the variable space a bit by putting all assets into a table. Then you have only one global variable for all the assets. That minimizes the chance of accidentally overwriting an existing variable.

T-Bone
Inner party member
Posts: 1492
Joined: Thu Jun 09, 2011 9:03 am

### Re: Trying to Get Rid of Globals

Just want to add that you can totally have local variables that are accessed from both love.load and love.draw, like this:

Code: Select all

local mpgisquote

mpgisquote= "Oui, my parents say I'm related to a horse"
end

function love.draw()
love.graphics.print(mpgisquote, 20, 20)
end


In that case the variable is local to the main.lua file and can't be accessed from other .lua files.

shatterblast
Party member
Posts: 136
Joined: Tue Dec 11, 2012 9:47 pm
Location: Dallas, Texas, USA

### Re: Trying to Get Rid of Globals

micha wrote: How would you transfer this data, if not via globals?
Well, my approach so far has been that if it doesn't make the software crash, make it "local".
T-Bone wrote:Just want to add that you can totally have local variables that are accessed from both love.load and love.draw, like this:

Code: Select all

local mpgisquote

mpgisquote= "Oui, my parents say I'm related to a horse"
end

function love.draw()
love.graphics.print(mpgisquote, 20, 20)
end


In that case the variable is local to the main.lua file and can't be accessed from other .lua files.
I gave thought to this before, and does not putting the locals into love.draw() add to the game loop instead of outside it? From my understanding, that would reduce performance overall.
Last edited by shatterblast on Thu Jun 05, 2014 7:02 am, edited 1 time in total.

miko
Party member
Posts: 410
Joined: Fri Nov 26, 2010 2:25 pm
Location: PL

### Re: Trying to Get Rid of Globals

shatterblast wrote:I do not consider myself a professional coder, but I pass it by as a hobby. To my understanding, it is standard etiquette to avoid global declarations. To my limited knowledge, I have made some globals into locals.
You need in terms of "scope" - usually, globals mean accessible in every place in the program, while locals mean accessible within current scope (usually function body). The rule of thumb is to make variables occupy as small scope as possible, but not smaller.
So, if you place

Code: Select all

local back_ground = love.graphics.newImage("background01.png")
as your first line of main.lua file, that makes it accessible only within this file. But as this is your only file (no require() used), in practice this variable is "global" (accessible from every place in your program).

The other rule of thumb is to create as small number of globals as possible. So I would do:

Code: Select all

local Assets={}
local Sounds={}
local States={}
local Animations={}

-- Images
Assets.back_ground = love.graphics.newImage("background01.png")
Assets.spritesheet1 = love.graphics.newImage("sparkle_set01.png")
...
-- States
States.animationState_Effects = "Effect_0"
States.animationState_Saphir = "Effect_Saphir_1"
States.soundState = "Sound_1"

-- Sounds
Sounds.sound03 = love.audio.newSource("explosion03.ogg", "static")
Sounds.sound04 = love.audio.newSource("explosion04.ogg", "static")

Assets.spritesheet1:setFilter("nearest", "nearest")
Animations.animation1 = newAnimation(Assets.spritesheet1, 192, 192, 0.1, 110)
end


Or better yet, assuming you need only references to animations, not images, do like this:

Code: Select all

local Assets={}
local Sounds={}
local States={}
local Animations={}

local spritesheet1 = love.graphics.newImage("sparkle_set01.png")
spritesheet1:setFilter("nearest", "nearest")
Animations.animation1 = newAnimation(spritesheet1, 192, 192, 0.1, 110)
end

function love.update(dt)
for k, animation in pairs(Animations) do
animation:update(dt)
end
end

function love.draw()
Animations.animation1:draw(100, 100)
end

That makes variable spritesheet1 truly local to the love.load() function.

Also, see http://lua-users.org/wiki/ScopeTutorial
My lovely code lives at GitHub: http://github.com/miko/Love2d-samples

shatterblast
Party member
Posts: 136
Joined: Tue Dec 11, 2012 9:47 pm
Location: Dallas, Texas, USA

### Re: Trying to Get Rid of Globals

miko wrote:The rule of thumb is to make variables occupy as small scope as possible, but not smaller.
So, if you place

Code: Select all

local back_ground = love.graphics.newImage("background01.png")
as your first line of main.lua file, that makes it accessible only within this file. But as this is your only file (no require() used), in practice this variable is "global" (accessible from every place in your program).

The other rule of thumb is to create as small number of globals as possible.

...

That makes variable spritesheet1 truly local to the love.load() function.
Thanks for the information! I will check to see how I can integrate this into my project.

kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Contact:

### Re: Trying to Get Rid of Globals

I am on my mobile and can't type much. Give a look at the bump 2.0 demo source code.

There's no global variables, just things required with require or passed by parameter.

For resource loading, there's a module called media.lua. It uses no global vars (only requires).
When I write def I mean function.

davisdude
Party member
Posts: 1154
Joined: Sun Apr 28, 2013 3:29 am
Location: North Carolina

### Re: Trying to Get Rid of Globals

I'm not sure if I'm the greatest role model here, but I guess you could take a look at how I do it.
I keep all variables local, except in the file called 'Globals.lua'. In this file I have all my globals, as well as any variables needed from other files that I might need. Then, I simply put 'require( Globals )()' and it calls the function that registers all of the global utilities (like entities and such).
GitHub | MLib - Math and shape intersections library | Walt - Animation library | Brady - Camera library with parallax scrolling | Vim-love-docs - Help files and syntax coloring for Vim

undef
Party member
Posts: 438
Joined: Mon Jun 10, 2013 3:09 pm
Location: Berlin
Contact:

### Re: Trying to Get Rid of Globals

Yep, like miko said.
Another performance boost can be gained by cashing lua functions to the scope of the file...

for example:

Code: Select all

local sin, pi, rand = math.sin, math.pi, math.random

for i=1, 1e100 do
local x = rand( i )
sin( pi*x )
end

This only really makes a difference if you use those functions very often, but I always do it, because:

1. it's shorter code
2. if I'm used to doing this I don't have to think about it when I really need it
twitter | steam | indieDB

Check out quadrant on Steam!

Xgoff
Party member
Posts: 211
Joined: Fri Nov 19, 2010 4:20 am

### Re: Trying to Get Rid of Globals

kikito wrote:There's no global variables, just things required with require or passed by parameter.
this

i avoid globals completely (unless i need to override a built-in for some reason). putting all of your "global" state into modules and requiring them on-demand (into locals!) makes it much easier to find that information in the future. not to mention you'll avoid accidentally creating two or more globals with the same name but different contents, which is easy to do when you don't have a declaration in your files anywhere!

about the only places where using "globals" are all that useful are with your own function environments, mainly for dsl-y things, since *usually* their existence will be limited to certain code only

### Who is online

Users browsing this forum: No registered users and 33 guests