
Share Your Code
Browse Code
- All (906)
-
(94)
-
(85)
-
(44)
-
(4)
-
(42)
-
(136)
-
(21)
-
(41)
-
(13)
-
(65)
-
(151)
-
(210)
Director Slim - Stripped down Director Class
I've managed to strip it down to only 15 lines of code! That's right. Plus 6 lines for the header.
Works faster, with lower overhead - hence higher performance.
UPDATE 2011-11-05: Reduced to 15 lines. Fully working example added to GitHub.
I didn't like director 1.3 when it came out, so I decided to stick with version 1.2a - the one with improved group cleaning function. I was fine with it thanks to Ricardo and Jonathan. Until I looked into the code more closely. Original source code size is over 500 lines long!
I am not using any of the effects - instead I created my own effects and call them directly from scene modules. So first thing I wiped out all the effects related stuff - there were tons of code for it. Next it was using way too many display groups - got rid of all of them! Now a localGroup you create in a scene module - is the top group, there are no groups above it like in the original director class.
Next I removed all unnecessary variables and functions. Also got rid of repeating code, collapsed several functions and optimized what's left.
And it doesn't use deprecated module() function.
Surprisingly, what I have got after such refactoring doesn't look like an original director class at all.
I must say, of course, that this module is not fully compatible with the original director class. You must use it only if you know what are you doing. You still use director:changeScene() function to change between scenes, however if you need to get a name of currently loaded module you use director.scene variable.
You DON'T need to write in main.lua
1 2 3 | director = require( "director" ) local mainGroup = display.newGroup() mainGroup:insert(director.directorView) |
Instead you just require the module and after it you can use director:changeScene() right away.
Sample main.lua file:
1 2 3 4 5 | director = require('director') local function main() director:changeScene('scene') end main() |
Sample scene.lua
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | -- Module table local _M = {} -- Some global variable that we want to clean on exit unboundedVariable = 100 -- Main function - MUST return a display.newGroup() function _M.new() local localGroup = display.newGroup() local goToMenu = function() director:changeScene( 'here_goes_another_lua_scene_module' ) end timer.performWithDelay(1500, goToMenu, 1) function _M.clean () -- Clear here everything what is outside this function scope or localGroup -- Don't do localGroup:removeSelf() _G.unboundedVariable = nil end return localGroup end return _M |
clean() function works as before. I fixed a major bug I encountered by using director 1.2a. The bug was that the clean() function was called only after a next scene is loaded - it was messing up my game and it was a final drop to start refactoring.
Now, here it is - Stripped down Director Class. In all it's glory.
director.lua
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | -- Director Slim - Stripped down Director Class -- Author: Lerg -- Release date: 2011-10-30 -- Version: 1.0 -- License: MIT -- Web: http://developer.anscamobile.com/code/director-class-24-lines-code local director = {scene = 'main'} function director:changeScene (moduleName) if type(moduleName) == 'nil' or self.scene == moduleName then return end local loadedModule = package.loaded[self.scene] if type(loadedModule) == 'table' and type(loadedModule.clean) == 'function' then loadedModule.clean() end if self.view then self.view:removeSelf() end if self.scene ~= 'main' and type(loadedModule) == 'table' then package.loaded[self.scene], self.view, loadedModule = nil collectgarbage('collect') end self.view, self.scene = require(moduleName).new(), moduleName end return director |
From the GitHub you can download complete sample showing how to use this module. It includes simple scene changing effect.
- Type:
- Tags:
Replies
Hi Lerg. Just looked for you on irc channel. Getting this eror.
director.lua:28: module 'main_menu' not found:resource (main_menu.lu) does not exist in archive
no field package.preload['main_menu']
It's OK, I see now, the "main_menu" needs to be a new scene i want to go to. So I have to make a main_menu.lua (another page)
Thanks
If anyone wants effects, try this on every page:
Instead of: local localGroup = display.newGroup()
Put:
local localGroup = display.newGroup()
localGroup.alpha = 0
local trans = function()
transition.to( localGroup, { time=1500, alpha=1.0} )
end
trans()
So, if i choose to use this director, will I have to go back and change all the references to the old director?
Thank you. Also fixed 'main_menu' issue - renamed it to be obvious.
You just need to replace old director.lua with this director.lua.
Also remove from main.lua
1 2 | local mainGroup = display.newGroup() mainGroup:insert(director.directorView) |
And if you are lucky you won't need to change anything else. Basically if you are not using director effects and use only director:changeScene('scene_name') function - you are fine.
Also it must be noted that behavior of display objects outside localGroup have slightly changed. If they are instantiated in a new() function, then you might need to call localGroup:toFront() to make it appear above those objects.
Thanks Lerg. This has eliminated a flicker problem I get with Director1.4 on a scene change.
With yours, I can't get the clean to trigger. I have spent hours trying things as I look through the code, but obviously I am not understanding things.
In your sample scene you start with local _M = {}. Is that required? I have not done that in Director. I tried setting up my scene the same way, but no success.
With Director1.4, I can get clean to trigger two different ways:
function clean ( event ) -- I have this after module ( ..., package.seeall )
print("clean function")
end
or
localGroup.clean = function()
print("cleaned from localGroup.clean")
end
On line 21 of your code it looks like it calls the clean(), but I get nothing.
From line 20, it looks like a table is required.
On a different note, in main.lua I have been declaring
local director = require('director'), but I see you are using global. Is that important?
Any ideas would be most appreciated.
Hi flyingaudio,
I've added a complete fully working example for the Director Slim, please download it from GitHub. It has clean() function calls with both module definitions, also it has nice scene changing effect included.
module ( ..., package.seeall ) - this thing is deprecated, try not to use it. Instead local _M = {} thing is introduced.
director variable should be global in main.lua. Local would not work.
See clean() functions in the example.
That did it Lerg.
I didn't realize _M was replacing module, so I had both.
You're examples are great.
Your 24 line solution had a cleanGroups section after a getmetatable thingy. Is your 15 line solution still doing all that cleaning, or do I need to cover that somewhere else (whatever that stuff maybe)?
There is one thing that broke, so I will figure out a different way to do it. With Director1.4 I can changeScene( { myParm = var}, "new scene" ) to pass a parameter into the new scene, but not with your version.
Thank you for sharing your work on this tight abbreviated version of Director.
flyingaudio,
It still does all the cleanup. cleanGroups() was intended for very very old corona builds, so I removed it. There is still one case in which this function would be useful, but whoever need it can put this function back on their own (it's when you override default :removeSelf() function).
For passing parameters you can use different ways.
1) Attach parameters to director class:
1 2 | director.params = {myParam = var} director:changeScene(...) |
and in the scene file:
1 | local myParam = director.params.myParam |
2) Attach it to a global table. It's like first one, but you don't use director:
1 2 | params = {myParam = var} director:changeScene(...) |
and in the scene file:
1 | local myParam = params.myParam |
3) Use setOption() and getOption with this module http://pastebin.com/Wmgt262x. Require it in main lua as
require('options')
1 2 | setOption('myParam', var) director:changeScene(...) |
and in the scene file:
1 | local myParam = getOption('myParam') |
Lergs,
Thanks for clarifying each point. It works like a charm. I practiced methods 1&2 above. Since they are both global, is there any advantage to either one?
Thank you SO MUCH for this Lerg! As much as I appreciate Ricardo's efforts and continued support/enhancement of Director, there seems to be a "trend" in coding to just add, add, add, with little regard to the bloat, weight, and overall efficiency of the module (subtle it might be, but on mobile devices you can never have something "too light").
So thank you for providing this code. I have already been using my own "lite" Director based on version 1.2, but it's around 100 lines versus your ultra-lite 15. :) So I will try to implement yours soon, especially since (like you) I tend to put the transition effects directly into the modules, or into "main.lua" itself.
Brent Sorrentino
Ignis Design LLC
flyingaudio, there is not much difference between those methods, use whichever suits you better.
IgnisDesign, totally agree. You are welcome.
License: MIT?
Looks very interesting and because of the benefits I'm very interested.
However, what are the implications if I use this in my application and/or game and publish it in the App Store and/or Android Market, etc.... and I earn cash?
-- Director Slim - Stripped down Director Class
-- Author: Lerg
-- Release date: 2011-10-30
-- Version: 1.0
-- License: MIT?
Thanks, and look forward to your continued publications!
Hi mobilefun4me,
Why didn't you google the license meaning? It's one of the most popular freeware licenses.
You can do almost whatever you want with this code. Definitely can use it for your paid apps.
Corona "ui.lua" Issue/Concern
Thanks Lerg:
I tried using the Corona "ui.lua" on my menu screen and when the code ran the following, the program hung:
-- Insert and run dimming effect
localGroup:insert(dimRect)
transition.to(dimRect, {time = effects.dimDelay, alpha = 0})
-- MUST return a display.newGroup()
return localGroup
It appears that when it ran through Director Slim, it returned to main.lua
I just added a normal button image in the sample code and everything was just great, but ui.lua seems to give it fits.
Thanks!
mobilefun4me,
when it hangs try to put a simple print('whatever') before return localGroup line. I think Corona might not like sometimes initiating transitions right before the function end.
Lerg, is there a way to delete all previous scenes? I get to my main game I don't want to have all the texture from the previous scenes slowing down my game.
I don't see any cleaning functionality in your code?
Hi dubcanada,
There shouldn't be any problems with object removal. As long as you attach everything to localGroup or remove it yourself in clean() function it should be fine.
As soon as all objects using a certain spritesheet are deleted that asset is removed from the texture memory.
It is calling garbage collector on each scene change so that should wipe all the garbage out for sure.
Lerg,
Now that Storyboard is out, will you use it, or stick with your Director Slim? Why?
flyingaudio,
I will consider Storyboard later. Director Slim advantage is that it's super simple and I know exactly what's going on inside it. Can't say the same for Storyboard.
Lerg, got your sample from Github and its running fine, so I added a few objects to the scene_modern.lua file (to simulate a level for example), anyway, I added some display objects then add them to the local group, then i added a runtime event handler for enterFrame, basically to move the group of objects around, everything still works fine and enter frame code executes.
The problem is, when i use Runtime: then the click to go back fails to work. Can I use Runtime: to add an event hander for enterFrame inside these scene.lua files? Or where / how would i create handlers for enterFrame etc?
hope this makes sense :)
anyway, really like your solution and hope to use it.
thanks
any ideas?
thanks
Hi bragbase,
Your issue doesn't ring a bell for me. Runtime listeners should work just fine if they are properly handled. My guess it has nothing to do with the click event.
You can zip and leave a link to your setup so I can run it and see what's wrong.
You are right its not the click event, i am just not sure where to place the scene specific runtime listeners.
Will see if i can zip up some time, can I email it to you?
bragbase, do you get any errors when you click to go back? My guess is that you trying to use a group in the enterFrame listener which is no longer available (removed).
Have you tried to remove the listener in the clean function?
There is no messaging system on the site so I can't tell you my email privately.
Really nice. Going to try to setup it along with your pause timers and transitions code.
I really need the following effect from the old director class.
1 2 3 4 5 6 7 | if effect == "moveFromRight" then nextView.x = _W nextView.y = 0 -- showFx = transition.to( nextView, { x = 0, time = fxTime } ) showFx = transition.to( currView, { x = -_W, time = fxTime, onComplete = fxEnded } ) |
What's the nicest way to do this ? Implement it within effects.lua ?
Pasz72, no support for such effect.
Consider storyboard as well in this case.
Works great....thank you very much.
Love this reduced size Director! I was wondering if anybody has an app(s) out that uses this? So far i do not see any issues on my own upcoming app but I am very interested in knowing if apps in the wild are running fine.
Thanks for sharing this piece of amazing code!
Mo
Hi Lerg,
Once again, thank you for the excellent and light piece of code for "Director Slim". As I try to understand what's going on behind the scenes with your code, my question is this:
What is the essential purpose of the "clean()" function built into each template? I think this was at some point "callClean()" in the original Director...
As far as I can tell, on scene change, it's calling this function, but perhaps the purpose eludes me. All I want to do is this:
1) clear the display objects in the scene (already done via "self.view:removeSelf()").
2) completely clear/void the module and its functions from memory, which appears to happen in these lines (it removes it from Lua's "package.loaded" table):
1 2 3 4 | if ( self.scene ~= "main" and type(loadedModule) == "table" ) then package.loaded[self.scene], self.view, loadedModule = nil collectgarbage("collect") end |
Assuming that I manually clear/nil my listeners, timers, etc. before changing scenes, shouldn't the above 2 steps fully and permanently clear out ALL aspects of the scene and free up its memory completely?
If so, what is the purpose of calling the "clean()" function within the scene being cleared? I'm sure there's a good and valid reason, but again, it's somehow eluding me...
Any help is appreciated; I genuinely hope to use your Director Slim versus Director 1.4 (now 2000+ lines, albeit 1000+ lines are probably comments and blank lines). I also hesitate to use Storyboard, which is very promising but seems to have a few thorny issues, minor bugs, and performance issues at this point.
Sincerely,
Brent Sorrentino
Ignis Design
Hi IgnisDesign,
clean() function in your module should wipe out everything that is not possible to clean by director module. Such as globals, timers, something in other modules, maybe connections and files. Rule is when you use something in the scene think about how to clean it later right away, in case of local objects inside the localGroup you don't have to do anything special.
Yes this function is called on scene change.
Yes, it should.
You can put your timers/listeners clean up code inside the clean() function and it would be called automatically - that's all.
I hope this helped.
First of all, thank you for a great piece of code.
If I have a seperate file I want to include in one of my scenes (let's say ui.lua), do I have to edit this file in the same way as your example (adding the _M module) or will director take care of it as long as it is called (and required) from within the _M.new function in my scene?
Dr.Mabuse,
Thank you for thanking.
It's better to avoid module(..., package.seeall) stuff and use _M style everywhere. But you don't have to actually. It will work both ways.
Just to check if I understand this correctly; if I want to implement a 3rd-party tool like Lime, Text Cady or Particle Candy, I then have to edit all their lua-files and add the _M stuff to these?
Dr.Mabuse,
No, you don't have to.
Man, this is really great and solved some of the issues my game was having!
I have a question though, how would I reload my scene with this?
Let's same the player dies in my game and I want to reload the same level, how would I go about doing this?
Axie Studios,
Hi make a restart.lua with similar content to this:
1 2 3 4 5 6 7 8 9 | local _M = {} function _M.new() local localGroup = display.newGroup() timer.performWithDelay(100, function () director:changeScene('level') end) return localGroup end return _M |
Which come backs to the level view.
Lerg, thanks a lot man! Works perfectly!
Amazing job on this whole class man.
One question: If I call changeScene("A") from function a:method(), director will then call a:clean() and then return back to function a:method(). But "a" has already been cleaned. Is this a problem for Lua? Do I have to be really careful not to have code in function "a" following the call to changeScene?
I am a bit uncomfortable with code where code "a" calls code "b" calls code "a". Warning for endless loops and all.
Thanks for the code Lerg.







Will try this out now, thanks Lerg! Looks cool, clean and short.
Like you said, if people want effects then they can add them in.
Especially like the non module code (which you have been using for a long time, before we all realised)
I was doing my own, but it was taking too long, rather leave general functional stuff to the masters, until I become one.
Will use this along with your awesome pause timers and transitions!