## How to use local variables in games properly?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
ilovelove2019
Citizen
Posts: 78
Joined: Wed Sep 11, 2019 10:38 am

### How to use local variables in games properly?

Hello everyone, I just learned how to program games, when I encounter bugs, I often ask the community for help. Some people have read my code and they say there's a lot of instability, it's about me abusing the global variable. They advised me to use as many local variables as possible because it helps me limit the risk. But now I still can't fully understand it.
They said I should apply the local variable to my code. And I see, when using local variables, accessing it elsewhere becomes extremely difficult. So today, I want to ask you some questions:
• * Firstly, in my particular case. They say listOfFruits and listOfBlock must be local. When I fixed it to local, I got an error with the Apple.lua file, saying that I cannot access listOfFruits. Take a look at my specific code, you will understand my case. I want to program with local variables the right way, using it as much as possible.
Please take a look and adjust my code so listOfFruits and Apple.lua still work well, help me.

* Secondly, I need a correct game structure. Some helpers, they also told me I had to restructure my game to make it easier to use local variables and manage objects. But I don't know what I should do. Please help me, read through my code and refactor so I can use local properly,
But don't get too far from the current structure. If you give me specific examples, I would be very happy. For example, now I need a way to manage the bottles in the game, add it in main.lua, manage itself in bottle.lua, some functions of the bottle are to destroy it from the world. , update, ... In the example,
You try to come up with a few cases which require access to variables from elsewhere. You just need to write a sample for me 2 files, then I will read and understand that code, later I can program the game properly. For me to imitate is the fastest way of learning (of course, I have to understand it too). I know I have a lot of demands,
This is my code: main.lua

Code: Select all

--- require libs
Object = require "codes/libs/classic"
bump = require "codes/libs/bump"
anim8 = require "codes/libs/anim8"

-- create new world
world = bump.newWorld()
---------game variables
listOfBlocks = {}
listOfFruits = {}
isRequired = false
currentLevel = 1
local background = love.graphics.newImage("sources/arts/tiles/tiles.png")
--- require
if isRequired == false then
require "codes/entities/characters/knight"
require "codes/entities/blocks/block"
require "codes/entities/items/fruits/apple"
isRequired = true
end

initGame()
end

function love.update(dt)
--- update player object
player:update(dt)
end

function love.draw()
--- draw background
drawBackGround()
--- draw blocks
for i,v in ipairs(listOfBlocks) do
v:draw()
end
--- draw fruits
for i,v in ipairs(listOfFruits) do
v:draw()
end
--- draw player object
player:draw()
end
---- keyboard event
function love.keypressed(key)
if key == "w" and player.onGround then
player.yVelocity = player.jumpVelocity
end
end
--- blocks
map = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 1, 2, 2, 2, 1, 0, 0, 0, 0, 1, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}
buildMap()
--- fruits
table.insert(listOfFruits, Apple(256, 64, 1))
table.insert(listOfFruits, Apple(128, 16, 2))
table.insert(listOfFruits, Apple(512, 400, 3))
table.insert(listOfFruits, Apple(256, 128, 4))
end
--- build map for all level with the data in function loadMapLevel'i'
function buildMap()
--id : 1.grass 2.dirt
for y = 1, 15 do
for x = 1, 30 do
if map[y][x] == 1 then
table.insert(listOfBlocks, Block((x - 1) * 32, (y - 1) * 32, 1))
elseif map[y][x] == 2 then
table.insert(listOfBlocks, Block((x - 1) * 32, (y - 1) * 32, 2))
end
end
end
end
--- init the game
function initGame()
-- create player
end
local who = name
local xPos, yPos = x, y
if who == "knight" then
player = Knight(xPos, yPos)
end
end
--- draw background
function drawBackGround()
if currentLevel == 1 then
for i = 10, 16 do
end
--- draw background---
for i = 1, 30 do
end
end
end
knight.lua:

Code: Select all

Knight = Object:extend()

function Knight:new(x, y)
self.x = x
self.y = y
self.width = 32
self.height = 48
self.scaleX = 1
--- art
self.sprite = love.graphics.newImage("sources/arts/characters/knight/knight.png")
self.grid = anim8.newGrid(self.width, self.height, self.sprite:getWidth(), self.sprite:getHeight())
self.animations = {}
self.animations.idle = anim8.newAnimation(self.grid(1, 1, 2, 1, 3, 1, 2, 1), 0.1)
self.animations.walk = anim8.newAnimation(self.grid(4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 4, 1), 0.05)
self.anim = self.animations.idle
---- collision properties
self.colWidth = 16
self.colHeight =  24
--- physics properties
self.xVelocity = 0
self.yVelocity = 0
self.gravity = 1000
self.terminalVelocity = 800
self.onGround = false
self.jumpVelocity = -400
end

--- knight collision filter
local function knightFilter(item, other)
if other.isBlock then return "slide"
elseif other.isApple then return "cross" end
end

function Knight:update(dt)
--- moveleft and right
if love.keyboard.isDown("a") then
self.xVelocity = -100
self.scaleX = -1
self.anim = self.animations.walk
elseif love.keyboard.isDown("d") then
self.xVelocity = 100
self.scaleX = 1
self.anim = self.animations.walk
else
self.xVelocity = 0
self.anim = self.animations.idle
end
--- apply gravity
if self.yVelocity < self.terminalVelocity then
self.yVelocity = self.yVelocity + self.gravity * dt
else
self.yVelocity = self.terminalVelocity
end
--- apply to move with bump
local goalX, goalY = self.x + self.xVelocity * dt, self.y + self.yVelocity * dt
local actualX, actualY, cols, len = world:move(self, goalX, goalY, knightFilter)
--- check for collision
self.onGround = false
for i = 1, len do
local col = cols[i]
local other = cols[i].other
if (col.normal.y == -1 or col.normal.y == 1) and col.other.isBlock then
self.yVelocity = 0
end
if col.normal.y == -1 and col.other.isBlock then
self.onGround = true
end
-- check collision with fruit
if other.isApple then
other:boom()
end
end
--- store real x, y
self.x, self.y = actualX, actualY
--- update animations
self.anim:update(dt)
end

function Knight:draw()
love.graphics.setColor(1, 1, 1)
self.anim:draw(self.sprite, self.x + 8, self.y + 4, nil, self.scaleX, 1, 16, 24)
love.graphics.rectangle("line", self.x, self.y, self.colWidth, self.colHeight)
end
block.lua:

Code: Select all

Block = Object:extend()

function Block:new(x, y, id)
self.x = x
self.y = y
self.width = 32
self.height = 32
self.sprite = love.graphics.newImage("sources/arts/tiles/tiles.png")
self.id = id
if self.id == 1 then
elseif self.id == 2 then
end
self.isBlock = true
end

function Block:update(dt)

end

function Block:draw()
love.graphics.setColor(1, 1, 1)
love.graphics.rectangle("line", self.x, self.y, self.width, self.height)
end
apple.lua:

Code: Select all

Apple = Object:extend()

function Apple:new(x, y, ripelevel)
self.x = x
self.y = y
self.width = 16
self.height = 16
self.ripelevel = ripelevel
self.sprite = love.graphics.newImage("sources/arts/fruits/fruit.png")
for i = 1, 4 do
end
self.isApple = true
end

function Apple:update(dt)

end

function Apple:boom()
for i = #listOfFruits, 1, -1 do
if listOfFruits[i] == self then
world:remove(listOfFruits[i])
table.remove(listOfFruits, i)
end
end
end

function Apple:draw()
love.graphics.setColor(1, 1, 1)
love.graphics.draw(self.sprite, self.quads[self.ripelevel], self.x - 10, self.y - 12)
love.graphics.rectangle("line", self.x, self.y, self.width, self.height)
end
Beside: this project still works but many people have warned me. Many past mistakes made me quit other projects because of the inappropriate local usage. Hope you help
Edit : The link to my current problem on Github: https://github.com/bananaback/Help-me-in-this
If I provide incomplete information then you just ask, I will provide as soon as possible

raidho36
Party member
Posts: 2063
Joined: Mon Jun 17, 2013 12:00 pm

### Re: How to use local variables in games properly?

You simply declare everything that doesn't needs to be globally accessible as local. That's it. Pass around values through function arguments if you need to. Making local duplicates of global variables helps with performance (but they don't track global variable changes). Don't go nuts with generating closures at runtime though, that's not compiled and is rather slow, doing it once is fine but doing things like creating in-place functions will really tank performance.

A pro tip on the house: if your code got completely borked and you have no idea what's wrong with it, rewrite it from scratch and make effort to keep it functioning as you go. You can try your luck from last known working version, but if your code is broken so badly that there's no way to fix it, it's probably because it has deeply embedded flaws in it, so it's a good idea to toss the entire thing into the trash.

Finally, the game code doesn't needs to be good, it just needs to function. As long as it works, it's fine. Famous example; Minecraft has some of the most godawful code you can find in a commercial project, it was so bad that Microsoft decided they'd rather spend additional ton of cash to rewrite it than maintain and upgrade existing codebase - and yet here we are.

ilovelove2019
Citizen
Posts: 78
Joined: Wed Sep 11, 2019 10:38 am

### Re: How to use local variables in games properly?

Ye, the game code doesn't needs to be good, it just needs to function.

ilovelove2019
Citizen
Posts: 78
Joined: Wed Sep 11, 2019 10:38 am

### Re: How to use local variables in games properly?

raidho36 wrote:
Sun Dec 08, 2019 11:27 pm
You simply declare everything that doesn't needs to be globally accessible as local. That's it. Pass around values through function arguments if you need to. Making local duplicates of global variables helps with performance (but they don't track global variable changes). Don't go nuts with generating closures at runtime though, that's not compiled and is rather slow, doing it once is fine but doing things like creating in-place functions will really tank performance.
Can you give me an example of: "Pass around values ​​through function arguments" and "making local duplicates of global variables"?

And... what it mean? "Don't go nuts with generating closures at runtime though"
So sorry, I'm so stupid

raidho36
Party member
Posts: 2063
Joined: Mon Jun 17, 2013 12:00 pm

### Re: How to use local variables in games properly?

Passing around values:

Code: Select all

local function do_many_things ( foo, bar )
do_things ( foo, 1, 2, 3 )
do_other_things ( bar, 'a', 'b', 'c' )
end
do_many_things ( table1, table2 )
Making local duplicates:

Code: Select all

local mmax, mmin, mabs = math.max, math.min, math.abs
local function do_math ( value )
return mmax ( mmin ( mabs ( value ), 1 ), 0 )
end
Generating closures (OK):

Code: Select all

local foo = 0
local function do_stuff ( bar )
foo = foo + bar
return foo
end
print ( do_stuff ( 1 ) )
print ( do_stuff ( 1 ) )
Generating closures (bad, generates new closures every time you call master function):

Code: Select all

local function make_function_that_does_stuff ( )
local foo = 0
local function do_stuff ( bar )
foo = foo + bar
return foo
end
return do_stuff
end
local do_stuff1 = make_function_that_does_stuff ( )
print ( do_stuff1 ( 1 ) )
print ( do_stuff1 ( 1 ) )
local do_stuff2 = make_function_that_does_stuff ( )
print ( do_stuff2 ( 10 ) )
print ( do_stuff2 ( 10 ) )

This, and many other useful things are discussed in the "Programming in Lua" book, and Lua user manual.

The "duplicates" example is technically also closures.

### Who is online

Users browsing this forum: No registered users and 11 guests