How to split code from main into separate .lua files without breaking everything - best practices

I have been working on a prototype for my game and have been making a lot of progress.  However, I am doing ALL of my coding directly in main.lua. I have a massive pile of spaghetti code in main and I know this is not good practice, and I should be creating different lua files pertaining to different aspects of the game.  Player.lua, Enemy.lua, Level.lua, etc…  

My question is how do I approach splitting all of my working code out into separate modules without breaking things?  

Specifically I am confused about the following:

  • I have code which acts like a camera and follows the player everywhere he moves (by moving the world display group in opposite direction).   When I start pulling out code into separate files, isn’t that going to break how the camera functions?

  • I have sprites and animations created directly in main.   What happens when those end up in another file?

  • I am using Tiled and have one map being loaded.  When I start to add scenes and now have to decide which levels are loaded, how do I make sure this separate code integrates well with the rest of the game? 

  • Collision detection and physics code is currently all in main.  How would I go about separating it out?

To summarize, I would like to take the next step and go from prototype (with all code in main.lua) to complete game with multiple levels, enemies, etc, but I kind of have no idea of where to even start…  

Would any one be able to give a concrete example of how I can begin to approach this?

There was in interesting discussion started by @RoamingGamer a while ago about this.  It came down to personal preference and the way everyone’s minds like to structure things in ways that are easy for them to keep organized, but may be confusing to others.

Personally, I use the Lord of the Rings approach and have one module to rule them all.  A master module or master table. My current project has 60 modules and this method has been very helpful in taming them.

I start with the master module

[lua]

– master_module.lua

local M = {}

  --master table

  local mt = {

  – I put all my master table stuff here

  – since lua doesn’t has loose data typing I start by assigning future modules the boolean value of false. 

  – Each module will place a reference to itself inside the master table - so its value is no longer false. 

  – If the value is false in the future, I know there was problem referencing the module.

    actions = false,

    characters = false,

    menus = false,

}

M.mt = mt

local function getSettings( ) return mt end

M.getSettings = getSettings

return M

[/lua]

I then make the child modules

[lua]

– actions.lua

local M = {}

local masterModule = require(‘master_module.lua’)

– this returns the master table ( mt ) from the master module

local mt = masterModule.getSettings() 

– the actions module places a reference to itself in the master table.

mt.actions = M 

return M

[/lua]

Now every module has access to every other module ( without generating circular reference errors) by simply calling on the master table ( mt ) 

I made a chart a while ago that shows one way to use this master module method.  You can see I was also using SSK (Roaming Gamer’s Super Starter Kit

CoronaModuleFlow.png

I don’t really use the composer for scene management anymore so my current scheme is different but the chart still gives the basic idea of the structure

Thank you for the detailed example.  So to make sure I’m understanding, if something in the actions.lua file needed something in the characters.lua file, I could simple write:

mt.characters.getHealth(obj)

And regarding setting each module to false at the start, I’m not sure I’m understanding the value of that.  Would you be performing a check somewhere else in code to see if it’s false? 

Also, do you happen to have the link to that post by @RoamingGamer that you mentioned?

Yes, for the 

[lua]

mt.characters.getHealth(obj)

[/lua]

I set the files to false out of habit so I don’t end up with mystery elements appearing later.  For example, if a movement module added a key to an object’s table like

[lua]

object.previousSpeed = 100

[/lua]

I like to have that key already exist in the object’s table for debugging purposes.  Also, while I’m debugging if something that should be and object or table comes back as boolean - I know where to look first for the problem.

Unfortunately, I can’t find RG’s post - it might be archived by now

Really appreciate it.  Definitely helps me with a starting point to work off of as I separate out my code.  

Also I believe this may be the topic you were referring to:

https://forums.coronalabs.com/topic/63854-when-does-it-make-sense-to-employ-a-module-instead-of-a-function-within-a-scene-file/

Yes, that looks familiar - although it wasn’t started by Ed (Roaming Gamer), he was the first one to respond.  Definitely check out the Super Starter Kit link above.

I would also recommend scanning through the three PonyWolf sample projects here:

http://docs.coronalabs.com/guide/programming/index.html#match-3-space-rpg

We worked a lot with PonyWolf to come up with good organizational samples but in the end it all comes down to complexity.

Like you, my first Corona app back in 2010 was a single main.lua and to this date, that game is very hard to maintain. I’ve tried multiple times to modularize it, but due to its age and quality, I’ve failed on several attempts to modularize it. It’s mostly due to not wanting to have to spend a ton of time testing a game that practically gets no downloads.  But my second app did get modularized. And like many people modules are not the first thing you want learn (nor probably should) when learning Corona and Lua. This is also one of the reasons that many people suggest that your first, second or even third app should be throw-aways that are used to learn how to do it right, then when you’re more comfortable, you commit to building your first well done app that’s well organized.

I think the first order of breaking down your app is to think of your app as scenes. If you have a help scene, credits scene, game scene, game over scene, menu scene, etc. then that’s a good first go at modularization. You can create a scenes folder too and work to declutter the folder with main.lua.

The next evolution past that is to think about your app in objects and procedures. I have a weather app, where my current conditions page and daily forecast share the same code to retrieve the weather from my service and populate a lua table that gets shared among scenes. That app also has color themes (light and dark), so that became a module (mostly table of data and a couple of functions).

Then I started working on a new game (sort of similar in nature to my very first game, but different/better art, deeper content, and side scroller instead of vertical scroller). In this case, I went full bore object thinking and had modules for the player that contained all the things that worked on the player, a boss module for handling bosses, an enemy module for handling run-of-the mill enemies. The game modules calls functions in the player object, enemy object ETC and I keep just game specific features in the game module.

Rob

Rob, thank you for the detailed explanation.  I think I will take your approach and start with scenes and then move to objects and procedures.  

If I could ask one follow up question regarding multiple levels… I have used Tiled to make just one level so far, but am planning on making around 40 levels total.  Do you recommend a scene for each level?  

The levels will be mainly the same - a pathway that the player will need to follow with enemy spawn points along the way, and possibly a few different exit zones which end the level.  I will also have a short timer (aprox 3 to 5 min) that the player will have to complete the level by, so they will not be super large levels. 

Thanks in advance!

Note, there might be some advantages to putting most of the sound module on main.lua instead of in its own sound module.  I’m not certain but I think it might clear up some unexplained sound issues that arise for me once in a while.  I still have to run more tests but I thought I’d mention that.

When it comes to Tiled, I’m really not your guy.

But in most cases, levels are made up of two things:  code and data. And frequently the code can be written in a way that it lets the data drive the activity. For instance if on level 1 you have two doors for the character to enter the scene and exit the scene and on level two you have two doors but at different Y locations, you can use the .y value of the doors to determine where to spawn the player.

So I don’t think I would have multiple non-data level files unless there are significant behavioral differences between levels.

Rob

@sporkfin    Thanks for mentioning.  I will be sure to thoroughly test the sound if I keep it out of main. 

@Rob       Appreciate the input.  I will see what makes more sense when I lock in what each level will be.