Standard Practice and 'Rules of Thumb'
Learning Flash, I remember thinking 'yeah - I know what I want - but where the hell do I start? I have a screen where most of the action occurs - but how do I get to that screen? Where do the scripts go - how do I get access to events? How do I connect my abstract objects with the GUI? Although Director projects can vary widely - from the restricted sandbox of Shockwave to unfettered projectors, from complex simulations to simple slideshows - there are a few basic rules of thumb helpful for getting started. Other developers will have their own practices - here's a few I use:
Practice 1 - Sprite 1
When starting with a new empty movie, I usually place a simple quick draw sprite (a rect outline with zero-width stroke) on sprite 1 and stretch it out over 100 or so frames (I will later trim or extend the length as needed). On to this sprite, I attach an empty placeholder behaviour called "Main" or similar, then lock the sprite.
By adding the "Main" behaviour to sprite 1, starting in frame 1, I know it will be the first behaviour instantiated. This behaviour's #beginSprite is where most of the startup action happens - creating abstract objects from parent scripts and so on. This behaviour is also used to connect sprite behaviours with each other or the abstract objects created by the "Main" script.
Some people use startMovie or prepareMovie as their 'Main' 'Start' function and store objects in global variables for later access - not a practice I recommend. I tend to use startMovie or prepareMovie only for executing one-off commands, such as registering Xtras or checking dependencies. If I want to start creating objects or interacting with other sprites - this is done in the beginSprite of Sprite 1.
Developing in Director is all about creating a system of interacting objects - and central to this is how you manage references. References are important because without a reference, an object dies. And without a reference, you have no way of communicating with an object.
References to behaviours instances are automatically created and stored in a sprite's scriptInstanceList when the playback head first hits that sprites. References can also be created using the script(), rawNew() and new() functions and manually assigned to a variable.
The "Main" script creates the main abstract objects, and stores the references in properties (or passes them on to another object for storing). When behaviours want to communicate with the abstract objects (or visa versa), they ask the "Main" object for a reference.
Practice 2 - Install a standard library of scripts
After adding the placeholder "Main" behaviour to sprite 1, the next step is to create a new castlib for a standard library of scripts I use in most projects - similar to whats available at http://www.lingoworkshop.com/Codelib/xlib/. Using an update utility (see http://www.lingoworkshop.com/code/classes/scripts/XLib.UpdateUtility.ls), I import the scripts - especially the ListLib (it may reflect an early interest in Lisp, but most Lingo I write involves working with lists).
Practice 3 - Keep the casts organised.
Standard scripts (from a generic library) go in their own cast, scripts specific to the project go in their own casts. If I am generating members on the fly, I have a cast called "TEMP" - I know that I can safely delete everything in that cast.
Practice 4 - Create Skeletons
Rather than trying to finish a script before starting the next, sketch out all the scripts before you start filling in the details. For example, say you have a text display and you want to open a browser when clicking on the hyperlinks, you might start by writing a behaviour for the text sprite like this
on beginSprite (me) -- create the wrapper object for opening a browser urlHandler = script("urlHandler") end on hyperlinkClicked (me, data, range) urlHandler.NavigateTo(data) end -- script("urlHandler") on NavigateTo (me, aURLstring) put me.string && " is navigating to " & aURLstring end
Later, you can determine whether you need to use BuddyAPI (or similar) to exert some more control over the browser, and actually write some code to open the browser - but in the meantime, you can use the message window to see if things are working the way they are meant to (so far).
It might sound like a trite statement - but plan to spend more time thinking about the 'big issues' of design and encapsulation rather than the details of implementation - particularly when the project is first starting.
Practice 5 - Scripting Conventions
Everyone seems to have their own convention. I'm too lazy to abide to some convoluted convention that manages to indicate that "mpl_i_Foo" is a 'public' property of type propertyList containing integers. My convention/rule is
- methods that are 'private' (that is, should not be called by other objects) begin with an underscore -- eg _Initialise)
- other methods are public (in the past, I've written method names commenceing with "m" - such as mInitialise() to distinguish them from built-in methods - but I've dropped this habit in recent years).
I don't bother with complex conventions for variables other than (when I remember to do this) first letter is Uppercase for object properties and first letter lower case for local variables. As I mentioned, some people try to indicate scope and type when naming variables. I tend to focus more on indicating the purpose of the variable. In principle, all properties should be private to an object and should only be interacted with via the object's interface (thus you shouldn't really need to know or care whether the property Foo is a property list of integers - you should be more interested in the methods of the object that might use that property). When debugging, checking for incorrect type (usually void) is relatively straightfoward. Trying to remember what a property is intended for can be more problematic. Therefore, the convention for naming variables is:
- Object properties begin with Uppercase
- Local variables begin with lower case
- Global variables are not used
- Be a descriptive as you can - you have 256 characters to use (a variable named "x" compiles into the same length token as a variable named "link_parser_LastCheckedNodeList_Index")