Scoping in Modular Classes?

I started a simple colour matching game to help me learn corona, but as my game has developed i’ve had to do some research into modular classes. using all the tutorials i could find I have created three files, main, gameScreen and gameFunctions.

my gameScreen file holds a function that when called displays all my UI display objects and the functionality of these objects is controlled by functions in the gameFunctions file. 

 but when I run the game in the simulator I always get an error for the display objects that are created in the other class file. 

the error is:

Attempt to index global ‘hintBtn’ (a nil value)

stack traceback:

    [C]: ?

    /Users/user/Desktop/ReTrispect/gameFunctions.lua:148: in main chunk

    [C]: in function ‘require’

    ?: in function <?:982>

    (tail call): ?

    /Users/user/Desktop/ReTrispect/main.lua:48: in main chunk

if I add local to the object mentioned it then gives me a new error:

Error loading module ‘gameFunctions’ from file ‘/Users/user/Desktop/ReTrispect/gameFunctions.lua’:

    /Users/user/Desktop/ReTrispect/gameFunctions.lua:148: ‘(’ expected near ‘:’

I didn’t just want to post all the code on here so I hope I’m explaining myself well. 

unfortunately we would need to see some code to see how you have things set up and how your calling them in order to help

I thought you might I just wasn’t sure which parts of my code to include as the file is quite large - 

my display objects are set up in a class that includes all display groups:

[lua]

– gameScreen.lua

local mainGroup = display.newGroup()

local shapes = display.newGroup()

local buttonBar = display.newGroup()

local colorPlaced = display.newGroup()

local correct = 0

local M = {}

local screenHUD = function ()

    display.setDefault(“background”, 255, 255, 255)

    colorPicker = display.newRect(buttonBar, 0, 828, 640, 133)

    colorPicker:setFillColor(240, 239, 232)

    blankBtn = display.newImage (buttonBar,“blankbtn.png”, 80, 840)

    yellowBtn = display.newImage (buttonBar, “yellowbtn.png”, 180, 840)

    redBtn = display.newImage (buttonBar,“redbtn.png”, 280, 840)

    greenBtn = display.newImage (buttonBar,“greenbtn.png”, 380, 840)

    blueBtn = display.newImage (buttonBar,“bluebtn.png”, 480, 840)

    hintBtn = display.newImage (buttonBar,“Checkbtn.png”, 280, 59)

    mainGroup:insert(buttonBar)

    timerText = display.newText( “0”, 102, 59, “Opificio Rounded”, 30)

    timerText:setTextColor(0, 0, 0)

    correctText = display.newText( correct…"/9", 500, 59, “Opificio Rounded”, 30)

    correctText:setTextColor(0, 0, 0)

    

    

end

M.screenHUD = screenHUD

return M

[/lua]

and my hint button function is set up in a gamefunctions.lua file like this:

[lua]

–Hint Button in gamefunctions.lua

function hintBtn:touch(e)

if(e.phase == “began”) then

    if(hint>0) then

        local function show()

         timer.performWithDelay (250, function(e)

         colorPlaced.alpha = 0 

         shapes.alpha= 0.5

        

         end

         ,1)

        end

    show()

    timer.performWithDelay(1500, function(e)

    colorPlaced.alpha = 1

    shapes.alpha=0

    end, 1)

end    

hint = hint - 1

print(hint)

end

end

[/lua]

Line 148 where the error is called is at the top of the function for the hint button 

Thank you for your response and let me know if you need the full files. 

Try to change

function hintBtn:touch(e)

to

hintBtn.touch = function(self, e)

and add

hintBtn:addEventListener( "touch", hintBtn )

I still get the same error, but I’m wondering if I have the event listener placed in the correct place? at the moment it is at the end of the function before end is called? But i’m wondering if it should be placed in the gameScreen.lua file and called when the display object is created? 

Thanks for your response! 

If you get the same error then it means error is somewhere else. Please number lines according to your file because I have no idea which line is line 148

unfortunately we would need to see some code to see how you have things set up and how your calling them in order to help

I thought you might I just wasn’t sure which parts of my code to include as the file is quite large - 

my display objects are set up in a class that includes all display groups:

[lua]

– gameScreen.lua

local mainGroup = display.newGroup()

local shapes = display.newGroup()

local buttonBar = display.newGroup()

local colorPlaced = display.newGroup()

local correct = 0

local M = {}

local screenHUD = function ()

    display.setDefault(“background”, 255, 255, 255)

    colorPicker = display.newRect(buttonBar, 0, 828, 640, 133)

    colorPicker:setFillColor(240, 239, 232)

    blankBtn = display.newImage (buttonBar,“blankbtn.png”, 80, 840)

    yellowBtn = display.newImage (buttonBar, “yellowbtn.png”, 180, 840)

    redBtn = display.newImage (buttonBar,“redbtn.png”, 280, 840)

    greenBtn = display.newImage (buttonBar,“greenbtn.png”, 380, 840)

    blueBtn = display.newImage (buttonBar,“bluebtn.png”, 480, 840)

    hintBtn = display.newImage (buttonBar,“Checkbtn.png”, 280, 59)

    mainGroup:insert(buttonBar)

    timerText = display.newText( “0”, 102, 59, “Opificio Rounded”, 30)

    timerText:setTextColor(0, 0, 0)

    correctText = display.newText( correct…"/9", 500, 59, “Opificio Rounded”, 30)

    correctText:setTextColor(0, 0, 0)

    

    

end

M.screenHUD = screenHUD

return M

[/lua]

and my hint button function is set up in a gamefunctions.lua file like this:

[lua]

–Hint Button in gamefunctions.lua

function hintBtn:touch(e)

if(e.phase == “began”) then

    if(hint>0) then

        local function show()

         timer.performWithDelay (250, function(e)

         colorPlaced.alpha = 0 

         shapes.alpha= 0.5

        

         end

         ,1)

        end

    show()

    timer.performWithDelay(1500, function(e)

    colorPlaced.alpha = 1

    shapes.alpha=0

    end, 1)

end    

hint = hint - 1

print(hint)

end

end

[/lua]

Line 148 where the error is called is at the top of the function for the hint button 

Thank you for your response and let me know if you need the full files. 

Try to change

function hintBtn:touch(e)

to

hintBtn.touch = function(self, e)

and add

hintBtn:addEventListener( "touch", hintBtn )

I still get the same error, but I’m wondering if I have the event listener placed in the correct place? at the moment it is at the end of the function before end is called? But i’m wondering if it should be placed in the gameScreen.lua file and called when the display object is created? 

Thanks for your response! 

If you get the same error then it means error is somewhere else. Please number lines according to your file because I have no idea which line is line 148

it appears that you would need to

  1. import gameScreen.lua
  2. then call screenHUD()

before you can even

  1. *import* gamefunctions.lua

since screenHUD() is responsible for creating the button that gameFunctions needs.

this means you CAN’T do this:

local gs = require( 'gameScreen' ) local gf = require( 'gameFunctions' ) gs.screenHUD()

instead, you have to do this:

local gs = require( 'gameScreen' ) gs.screenHUD() local gf = require( 'gameFunctions' )

the technical issue here is that the code in gameFunctions runs immediately, where gameScreen is delayed until screenHUD() is called.

however, splitting up related functionality like this makes for fragile code, and not how you want it in the long run.

"But i’m wondering if it should be placed in the gameScreen.lua file and called when the display object is created? "

yes, exactly. put ‘function hintBtn:touch(e)’ in the same file as where ‘hintBtn’ is created. and, of course, the function goes after the button creation. :slight_smile:

Thank you soo much for you help! I really appreciate it! 

your right I did have to import the game screen before calling functions, however I also adjusted my Game Screen file slightly allowing each of the display objects to be returned separately like this: 

 [lua]

– Display Groups 

local shapes = display.newGroup()

local colorPlaced = display.newGroup()

local correct = 0

local M = {}

local hintBtn={}

local screenHUD = function ()

    local hud = {};

    display.setDefault(“background”, 255, 255, 255)

    hud.mainGroup = display.newGroup();

    hud.buttonBar = display.newGroup();

    hud.colorPicker = display.newRect(hud.buttonBar, 0, 828, 640, 133)

    hud.colorPicker:setFillColor(240, 239, 232)

    hud.blankBtn = display.newImage (hud.buttonBar,“blankbtn.png”, 80, 840)

    hud.yellowBtn = display.newImage (hud.buttonBar, “yellowbtn.png”, 180, 840)

    hud.redBtn = display.newImage (hud.buttonBar,“redbtn.png”, 280, 840)

    hud.greenBtn = display.newImage (hud.buttonBar,“greenbtn.png”, 380, 840)

    hud.blueBtn = display.newImage (hud.buttonBar,“bluebtn.png”, 480, 840)

    hud.hintBtn = display.newImage (hud.buttonBar,“Checkbtn.png”, 280, 59)

    hud.mainGroup:insert(hud.buttonBar)

    hud.timerText = display.newText( “0”, 102, 59, “Opificio Rounded”, 30)

    hud.timerText:setTextColor(0, 0, 0)

    hud.correctText = display.newText( correct…"/9", 500, 59, “Opificio Rounded”, 30)

    hud.correctText:setTextColor(0, 0, 0)

    

    return hud;

    

end

M.screenHUD = screenHUD

return M

[/lua]

out of interest when you say “splitting up related functionality like this makes for fragile code, and not how you want it in the long run.”

what would be the preferred or better method? I have a lot of functions that are repeated throughout the game so is there a way I can separate these functions without making the code fragile?

i said that because, from i what i saw from your (only two) files, they were arranged as 1. i have visual elements over here (game screen), and 2. functions over here (gamefunctions). but as we saw, some of the functionality belonged to an element in the other file, so the two weren’t “hanging out together” as they could, and that caused problems.

tl;dr below :slight_smile:

giving a quick example of an app which has a Tab Bar at top and Menu Bar at the bottom, we could easily create TabBar.lua and MenuBar.lua to help organize the project. the TabBar gets all of the visual elements related to the tab bar (buttons, graphics, input fields) *as well as* the functions to go along with those elements (touch listeners, show/hide, etc). same goes for the Menu Bar.
the app is still modular, but the things inside of the modules are related by their *Role* in the app (i.e. “i do tab bar stuff”), rather than their *Type* (ie, “i’m a button and i’m with other buttons”).
this method of organization is a huge win already. (but nothing out of the ordinary, because it’s like doing object oriented programming, and our objects here are simply the larger visual components of the app.)

now, perhaps i have a listener function which could be used in both TabBar and MenuBar without modification. it’s ok to copy/paste that and put into each of the modules as it is. each one of these files is responsible for a component of the larger app and perhaps /now/ they have the same listener, but shortly down the road maybe the TabBar listener will be modified. suddenly they’re not the same, but it doesn’t matter because they each have their own version in their own small section of the app (their module file). and you won’t have to worry if other modules/components use that listener because it’s not shared – this is a good thing. at the *least*, bugs are easy to find because there will be only one file which needs to be checked (e.g., “when i click on the tab bar button, nothing happens”). 1. you know instantly where to start looking, and 2. you’re sure that any modifications in TabBar won’t affect the rest of the app.

for other “generic” functionality which really can be reused by any part of the app – like changing radians into degrees, timestamp into hours, minutes, seconds, etc – i think most projects usually end up having a “Utilities.lua” file for this reason. by having a common file like this, this functionality is easily accessed and reused across files. but these functions are usually different because they’re just “workers” – e.g., converting radians to degrees – and that’s always going to be the same no matter if i’m TabBar or MenuBar.

in my experience, there aren’t a lot of functions in Utilities.lua relative to the rest of the project (maybe 3 functions compared to 150 methods).

tl;dr

i would say: don’t worry so much about having functions which are the same or close to it copied around the app. a more important win is to use modules to better organize the code by Role not Type. that small change would have prevented the original issue and will prevent a lot of hassle in the future.

if you were already going down that path, then that’s perfect. i inferred a lot from the little info i had. :slight_smile:

Thank You so much dmccuskey, in all my research I struggled to properly understand what was needed and you have just made it very clear.   :smiley:

you’re welcome ! i’m glad i could help. :slight_smile:

it appears that you would need to

  1. import gameScreen.lua
  2. then call screenHUD()

before you can even

  1. *import* gamefunctions.lua

since screenHUD() is responsible for creating the button that gameFunctions needs.

this means you CAN’T do this:

local gs = require( 'gameScreen' ) local gf = require( 'gameFunctions' ) gs.screenHUD()

instead, you have to do this:

local gs = require( 'gameScreen' ) gs.screenHUD() local gf = require( 'gameFunctions' )

the technical issue here is that the code in gameFunctions runs immediately, where gameScreen is delayed until screenHUD() is called.

however, splitting up related functionality like this makes for fragile code, and not how you want it in the long run.

"But i’m wondering if it should be placed in the gameScreen.lua file and called when the display object is created? "

yes, exactly. put ‘function hintBtn:touch(e)’ in the same file as where ‘hintBtn’ is created. and, of course, the function goes after the button creation. :slight_smile:

Thank you soo much for you help! I really appreciate it! 

your right I did have to import the game screen before calling functions, however I also adjusted my Game Screen file slightly allowing each of the display objects to be returned separately like this: 

 [lua]

– Display Groups 

local shapes = display.newGroup()

local colorPlaced = display.newGroup()

local correct = 0

local M = {}

local hintBtn={}

local screenHUD = function ()

    local hud = {};

    display.setDefault(“background”, 255, 255, 255)

    hud.mainGroup = display.newGroup();

    hud.buttonBar = display.newGroup();

    hud.colorPicker = display.newRect(hud.buttonBar, 0, 828, 640, 133)

    hud.colorPicker:setFillColor(240, 239, 232)

    hud.blankBtn = display.newImage (hud.buttonBar,“blankbtn.png”, 80, 840)

    hud.yellowBtn = display.newImage (hud.buttonBar, “yellowbtn.png”, 180, 840)

    hud.redBtn = display.newImage (hud.buttonBar,“redbtn.png”, 280, 840)

    hud.greenBtn = display.newImage (hud.buttonBar,“greenbtn.png”, 380, 840)

    hud.blueBtn = display.newImage (hud.buttonBar,“bluebtn.png”, 480, 840)

    hud.hintBtn = display.newImage (hud.buttonBar,“Checkbtn.png”, 280, 59)

    hud.mainGroup:insert(hud.buttonBar)

    hud.timerText = display.newText( “0”, 102, 59, “Opificio Rounded”, 30)

    hud.timerText:setTextColor(0, 0, 0)

    hud.correctText = display.newText( correct…"/9", 500, 59, “Opificio Rounded”, 30)

    hud.correctText:setTextColor(0, 0, 0)

    

    return hud;

    

end

M.screenHUD = screenHUD

return M

[/lua]

out of interest when you say “splitting up related functionality like this makes for fragile code, and not how you want it in the long run.”

what would be the preferred or better method? I have a lot of functions that are repeated throughout the game so is there a way I can separate these functions without making the code fragile?

i said that because, from i what i saw from your (only two) files, they were arranged as 1. i have visual elements over here (game screen), and 2. functions over here (gamefunctions). but as we saw, some of the functionality belonged to an element in the other file, so the two weren’t “hanging out together” as they could, and that caused problems.

tl;dr below :slight_smile:

giving a quick example of an app which has a Tab Bar at top and Menu Bar at the bottom, we could easily create TabBar.lua and MenuBar.lua to help organize the project. the TabBar gets all of the visual elements related to the tab bar (buttons, graphics, input fields) *as well as* the functions to go along with those elements (touch listeners, show/hide, etc). same goes for the Menu Bar.
the app is still modular, but the things inside of the modules are related by their *Role* in the app (i.e. “i do tab bar stuff”), rather than their *Type* (ie, “i’m a button and i’m with other buttons”).
this method of organization is a huge win already. (but nothing out of the ordinary, because it’s like doing object oriented programming, and our objects here are simply the larger visual components of the app.)

now, perhaps i have a listener function which could be used in both TabBar and MenuBar without modification. it’s ok to copy/paste that and put into each of the modules as it is. each one of these files is responsible for a component of the larger app and perhaps /now/ they have the same listener, but shortly down the road maybe the TabBar listener will be modified. suddenly they’re not the same, but it doesn’t matter because they each have their own version in their own small section of the app (their module file). and you won’t have to worry if other modules/components use that listener because it’s not shared – this is a good thing. at the *least*, bugs are easy to find because there will be only one file which needs to be checked (e.g., “when i click on the tab bar button, nothing happens”). 1. you know instantly where to start looking, and 2. you’re sure that any modifications in TabBar won’t affect the rest of the app.

for other “generic” functionality which really can be reused by any part of the app – like changing radians into degrees, timestamp into hours, minutes, seconds, etc – i think most projects usually end up having a “Utilities.lua” file for this reason. by having a common file like this, this functionality is easily accessed and reused across files. but these functions are usually different because they’re just “workers” – e.g., converting radians to degrees – and that’s always going to be the same no matter if i’m TabBar or MenuBar.

in my experience, there aren’t a lot of functions in Utilities.lua relative to the rest of the project (maybe 3 functions compared to 150 methods).

tl;dr

i would say: don’t worry so much about having functions which are the same or close to it copied around the app. a more important win is to use modules to better organize the code by Role not Type. that small change would have prevented the original issue and will prevent a lot of hassle in the future.

if you were already going down that path, then that’s perfect. i inferred a lot from the little info i had. :slight_smile:

Thank You so much dmccuskey, in all my research I struggled to properly understand what was needed and you have just made it very clear.   :smiley: