Skip to content

Splitting Code Into Several Files

noooway edited this page Jan 15, 2017 · 14 revisions

In this part I'm finally going to split the main.lua into several smaller files.

In Lua, a main program can load external files using require function. When a file is required, the code inside it is executed. By default, the execution takes place in the global environment of the main program. Thus, every variable that is not declared local, will be visible in the main program. The local variables are accessible only from the file, and do not pollute the global environment. If the external file has a return statement, that would be the result of the require statement in the main program.

External files are typically arranged to return a table with all the necessary definitions. Auxiliary functions and variable are declared local and are not added to the resulting table.

For demonstration, suppose there is a greetings.lua file with the following content:

local greetings = {}  --(*1)

greetings.hello_message = "Hello from Greetings module."

function greetings.say_hello()
  print( greetings.hello_message )
end

local secret = "IDDQD"

function greetings.reveal_secret() 
  print( secret )
end

function make_mess()
   mess = "terrible"
end

return greetings --(*2)

In interpreter

> greet = require "greetings"   --(*1)
> greet.hello_message           --(*2)
Hello from Greetings module.    
> greet.say_hello()             --(*2)
Hello from Greetings module.    
> greet.secret                  --(*3)
nil
> greet.reveal_secret()         --(*3)
IDDQD
> mess                          --(*5)
nil
> greet.make_mess()             --(*4)
stdin:1: attempt to call a nil value (field 'make_mess')
stack traceback:
        stdin:1: in main chunk
        [C]: in ?
> make_mess()                   --(*4)
> greet.mess                    --(*5)
nil
> mess                          --(*5)
terrible

(*1): "greetings" is required. The .lua extension is omitted. The returned table is assigned to the greet variable.
(*2): both hello_message and say_hello are accessible from the greet table.
(*3): secret is declared local and can't be accessed from the interpreter. However, greet.reveal_secret function has access to it.
(*4): the make_mess definition is not prefixed with local nor with module table. This function becomes defined in the global namespace.
(*5): mess variable is initially empty in the global namespace. After call to make_mess function, mess variable becomes defined in the global scope, not in the greet table.

With such a simple approach it is necessary to be careful not to accidentally put a declaration in the global scope. Every declaration should be either local or go into greetings table. I plan to address this issue in the Appendix.

Following this scheme, in the current code it is necessary to move each table in a separate file and add a return statement returning this table.

local levels = {}
levels.current_level = 1
levels.gamefinished = false
levels.sequence = {}
.....
return levels

After that, in the main.lua it is necessary to require these files:

local ball = require "ball"
local platform = require "platform"
local bricks = require "bricks"
local walls = require "walls"
local collisions = require "collisions"
local levels = require "levels"

.....

Apart from that, the code rest of the code in the main.lua doesn't change.

The only thing I want to introduce in this chapter is vector module from HUMP. It allows to simplify some arithmetics

local vector = require "vector"

local ball = {}
ball.position = vector( 200, 500 )
ball.speed = vector( 700, 700 )
ball.radius = 10

function ball.update( dt )
   ball.position = ball.position + ball.speed * dt
end

function ball.draw()
   local segments_in_circle = 16
   love.graphics.circle( 'line',
			 ball.position.x,
			 ball.position.y,
			 ball.radius,
			 segments_in_circle )   
end

    Home
    Acknowledgements
    Todo

Chapter 1: Prototype

  1. The Ball, The Brick, The Platform
  2. Game Objects as Lua Tables
  3. Bricks and Walls
  4. Detecting Collisions
  5. Resolving Collisions
  6. Levels

    Appendix A: Storing Levels as Strings
    Appendix B: Optimized Collision Detection (draft)

Chapter 2: General Code Structure

  1. Splitting Code into Several Files
  2. Loading Levels from Files
  3. Straightforward Gamestates
  4. Advanced Gamestates
  5. Basic Tiles
  6. Different Brick Types
  7. Basic Sound
  8. Game Over

    Appendix C: Stricter Modules (draft)
    Appendix D-1: Intro to Classes (draft)
    Appendix D-2: Chapter 2 Using Classes.

Chapter 3 (deprecated): Details

  1. Improved Ball Rebounds
  2. Ball Launch From Platform (Two Objects Moving Together)
  3. Mouse Controls
  4. Spawning Bonuses
  5. Bonus Effects
  6. Glue Bonus
  7. Add New Ball Bonus
  8. Life and Next Level Bonuses
  9. Random Bonuses
  10. Menu Buttons
  11. Wall Tiles
  12. Side Panel
  13. Score
  14. Fonts
  15. More Sounds
  16. Final Screen
  17. Packaging

    Appendix D: GUI Layouts
    Appendix E: Love-release and Love.js

Beyond Programming:

  1. Game Design
  2. Minimal Marketing (draft)
  3. Finding a Team (draft)

Archive

Clone this wiki locally