Organizing your project

General discussion about LÖVE, Lua, game development, puns, and unicorns.
User avatar
easy82
Party member
Posts: 184
Joined: Thu Apr 18, 2013 10:46 pm
Location: Hungary

Organizing your project

Post by easy82 »

Hello guys!

I've seen LÖVE projects that:
A) Uses globals everywhere, which are easy to access from anywhere in the project, only need to include files once (e.g. in main.lua). Mari0 is large enough and does this if I recall corretly.
B) Uses a couple of globals that are tables with useful variables and functions.
C) Uses no globals, locally includes files as they are needed. This is what I do now.
D) Uses no globals, passes objects as references. This is what I used to do in C++, and as I see Bump2 does this.

So what do you suggest the best way is to organize my code?

Thanks in advance!
User avatar
Kingdaro
Party member
Posts: 395
Joined: Sun Jul 18, 2010 3:08 am

Re: Organizing your project

Post by Kingdaro »

If you prefer to do less typing, A and B. If you prefer to have your scripts' dependencies more concise, C and D.

I asked about this a little bit ago, and kikito gives a good answer: viewtopic.php?f=5&t=78086#p168852
User avatar
Reef
Prole
Posts: 33
Joined: Sun Mar 04, 2012 10:19 pm

Re: Organizing your project

Post by Reef »

This is something that I've been struggling with also. I'm working on a little learning project and I'm having difficulty avoiding global variables but I suspect it's just the way that I have structured my game.

What I would really like, is to see some high quality example projects that I can dig through well organized source code. I like this framework and the community because I can dig through .love files and everyone is willing to help. However, many of the projects people post here are incomplete or quick and dirty games done for jams. In some ways this is the nature of the framework (do it yourself / prototyping) and even Lua itself but I'd like some great, clean examples of how to structure and organize things. Wikis and tutorials are great for initial learning and understanding concepts but I'd like to work towards larger projects.
User avatar
Inny
Party member
Posts: 652
Joined: Fri Jan 30, 2009 3:41 am
Location: New York

Re: Organizing your project

Post by Inny »

IMHO the best way to go is probably going with Globals for your classes, and locals for all of your instance variables. If you can pull off all-locals, just because you're that awesome, then go for it. But it's probably best to just load all of your code before or during love.load, and not have to worry about it.
User avatar
OttoRobba
Party member
Posts: 104
Joined: Mon Jan 06, 2014 5:02 am
Location: Sao Paulo, Brazil

Re: Organizing your project

Post by OttoRobba »

I do mostly A and B - maybe I shouldn't but I do.

A quick sample of my workflow:

Code: Select all

--timer.lua
local timer = {}
timer.new = function()
--code
end
return timer
It is then required by main.lua so, akin to working with HTML, everything is referenced in one place.

Code: Select all

--main.lua
timer = require "core/timer"
This way, say I want a timer within the defeat screen (think Street Fighter's continue screen), I could easily do

Code: Select all

--continueScreen.lua
local timer = timer.new(10)
And if I wanted a timer for the actual fight, I would just as easily do, in the fight.lua or whatever you wanna call:

Code: Select all

--fightScreen.lua
local timer = timer.new(99)
The downside is, like is said in Kikito's post that was linked, it is not immediately clear what is used where - any semantic or argument changes I did to this timer would need to be redone across multiple files.

The upside is that I can define a new local timer for each game state and I basically always have it written the same way.

Code: Select all

--continueScreen.lua
local timer = timer.new(10)
timer.set(20)
That is, for me, semantically better than doing something like this:

Code: Select all

--continueScreen.lua
local timer = require "core/timer"
local continueTimer = timer.new(10)
continueTimer.set(20)
TL, DR:
The less I have to type, the better. More lines of code means I'm more likely to make mistakes.
I like referencing things from a single file - I can, at a glance, know every module I'm using and it is easier to disable something across multiple files.
It is not as safe as a local require but I'm not too worried about perfect sandboxing.
User avatar
Xgoff
Party member
Posts: 211
Joined: Fri Nov 19, 2010 4:20 am

Re: Organizing your project

Post by Xgoff »

C

if i see a variable and can't find its declaration in the same file, i ain't gonna be happy

sandbox/dsl function environments are an exception of course (the other being the standard lib, obviously)
User avatar
Plu
Inner party member
Posts: 722
Joined: Fri Mar 15, 2013 9:36 pm

Re: Organizing your project

Post by Plu »

Depends on what I'm building. If it's a gamejam, where I work on a project for a short time with high intensity, I'll just global everything.
If it's a project I'll work on for a longer time but in short bursts, I'll use more locals.

The reason for is that if you use globals, only a small part of the project's structure is captured in your code; the rest of it is in your head. This is fine as long as you will complete the project before that structure has time to decay, but it's terrible if you want to work on the project for a longer time.

Using a lot of globals is kind of like working with an editor that will occasionally delete your comments and rename classes you haven't touched in a while; sure, everything will continue to work but it'll be confusing as hell after a while. You'll want to capture your structure in a place where it isn't likely to decay if you expect to be using it later. And "in the code" is about the best place to do it, but it'll take some extra effort in setting things up.
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: Organizing your project

Post by kikito »

D. No exceptions.

One particular example I can think on the bump.love demo: I wanted to make a screen shake effect when a grenade exploded.

This means that the grenades need to "know" the camera object - so they get it as a parameter in their constructor. And then it gets assigned to a member variable: self.camera = camera

This means that the entities which create grenades (Guardians) need to have a reference to the camera object, so they can pass it to the grenades they create. So they get it as a constructor and as an attribute.

The same thing happens with the Map, which creates the Guardias. It needs a reference to the camera, so it gets a constructor parameter and an attribute for the camera.

All that could have been removed if I had used a global variable. I would have typed much less.
OttoRobba wrote:The less I have to type, the better
I generally agree with this statement. The more code you write, the more you increase the possibility of making a mistake. The only infallible code is the code which doesn't exist.

And yet, I choose to write more here. Why?

For the same reason I return the classes as local variables require instead of making them global: Explicit dependencies make code easier to read.

Writing little code is important, but it is much more important to make that code readable. This is because we read code much more often. You can write code once, and then read it many, many times. The costs of the extra key presses to make the code easier to read is minimal compared to the effort it takes to understand the code by reading it many times.

Global variables make dependencies implicit: you have to remember in your head that they are there. You have to "allocate mental space" for them in your head while reading code.

Locals, parameters and requires are explicit: you must remember less things about them while reading code. You have some "extra mental space" in your head that you can dedicate to understanding the rest of the code. That is why I think they make code easier to read.

So, go D (and C - use local xxx = require 'xxx')
When I write def I mean function.
User avatar
easy82
Party member
Posts: 184
Joined: Thu Apr 18, 2013 10:46 pm
Location: Hungary

Re: Organizing your project

Post by easy82 »

Kingdaro wrote:If you prefer to do less typing, A and B. If you prefer to have your scripts' dependencies more concise, C and D.
I do like to type less, and to have less noisy code, because it's much easier to read. But I think as a project scales it's more and more difficult to understand and to extend it if I use globals.
Reef wrote:What I would really like, is to see some high quality example projects that I can dig through well organized source code. I like this framework and the community because I can dig through .love files and everyone is willing to help. However, many of the projects people post here are incomplete or quick and dirty games done for jams. In some ways this is the nature of the framework (do it yourself / prototyping) and even Lua itself but I'd like some great, clean examples of how to structure and organize things. Wikis and tutorials are great for initial learning and understanding concepts but I'd like to work towards larger projects.
Have a look at the sources of Mair0 (http://stabyourself.net/mari0/), Project Hawkthrone (http://projecthawkthorne.com/), Mr Rescue (http://tangramgames.dk/games/mrrescue/) to name a few. I think they prepresent very different coding styles, and they are certainly not jam games.
Inny wrote:IMHO the best way to go is probably going with Globals for your classes, and locals for all of your instance variables. If you can pull off all-locals, just because you're that awesome, then go for it. But it's probably best to just load all of your code before or during love.load, and not have to worry about it.
It's appealing, and I might end up with this one. Some people thinks globals are evil. :)
OttoRobba wrote:The less I have to type, the better. More lines of code means I'm more likely to make mistakes.
This is also true!
Xgoff wrote:if i see a variable and can't find its declaration in the same file, i ain't gonna be happy
I also like to declare my variables explicitly.
kikito wrote:Locals, parameters and requires are explicit: you must remember less things about them while reading code. You have some "extra mental space" in your head that you can dedicate to understanding the rest of the code. That is why I think they make code easier to read.
Also if you go back to your project after one or two months, it's good to see immediately what's going on.

Great, thanks for your suggestions and opinions!
It's not that I'm coding a very large game, I just want to develop good lua coding habits. :)
User avatar
MadByte
Party member
Posts: 533
Joined: Fri May 03, 2013 6:42 pm
Location: Braunschweig, Germany

Re: Organizing your project

Post by MadByte »

What kikito said with one exception.
Things I need often everywhere in my source code and which would increase the amount of characters in some lines drastically get declared global for me. Example : the screen width and height. I use them a lot to position stuff correctly and I dont want to type "love.graphics.getWidth()" every time nor do I want to write "local _width, _height = love.window.getDimensions()" in every single lua file I use them in. so I declare them one time in the main via "WIDTH, HEIGHT = love.window.getDimensions()".
But as you can see, if I create a global var I write it in uppercase letters so I don't get problems with any local width, height vars.
Besides that, I do everything local.
Post Reply

Who is online

Users browsing this forum: Google [Bot] and 203 guests