 |
| |
| |
| ActionScript
conventions (by Robert Tatsumi) |
|
· |
Keep actions
together. As much as possible, all code should be
placed one location (preferably frame 1). This makes
the code easier to find and debug. One of the main obstacles
in debugging Macromedia Flash movies is finding the
code. If most (or all) of the code exists in one frame,
then this problem is eliminated. There may be exceptions
to this rule. For example, when you are creating a pre-loading
Flash movie, you may find it impossible to place all
the code in frame 1. However, you should strive to place
all your code in a centralized location. |
|
· |
Use #include
.as files. This recommendation is mainly for larger,
more complex movies. This practice is also helpful when
multiple people are working on the same SWF. One of
the main benefits of using include files is to allow
the use of a source control system. This makes versioning
and comparing code easier to manage. |
|
· |
Frames
as application states. Use keyframes to delineate
application states. Currently, many developers to use
frames as states of the application and use inline code
within a frame action to define the state of the application.
This practice is not recommended. A better approach
involves organizing the code, placing any actions necessary
for this state into a function, and then calling the
function as the only action performed on that frame.
Alternately, an optimal strategy for organization involves
creating two layers in your movie. One layer extends
the full length of the movie and the majority of the
code is located within this layer/frame. The second
layer includes actions necessary for keyframe/state
changes of the application. The only code on each keyframe is a function call into the main frame where the
function exists. |
|
· |
Movie
clip actions are discouraged. Movie clip actions
should only be used when absolutely necessary. If used,
only a minimum amount of code should be included, as
in the following example:
onClipEvent(mouseDown) {
_rotation += 15; // rotate the movie clip by fifteen degrees
} |
|
· |
Initialization.
Use initialization code in your application to set the
initial state. This should be the first call of the
application. It should also be the only call made in
your program. All other calls should be event-driven
(for example, triggered by a frame event, a mouse event,
and so on), as in the code below:
// frame 1
this.init();
function init() {
if
(this.inited != undefined) {
return;
}
this.inited = true;
// do initialization here
} |
|
· |
Scoping
variables. All variables should be scoped. The only
variables that are not scoped are function parameters
and local variables. Absolute scoping (_root.myMovieClip.myVar.blah
= 100) can lead to non-portable code. If variables are
scoped to "this" and "_parent",
the resulting code will be easier to port later. Use
var for local variables. This prevents them from being
accessed globally. |
|
· |
Use relative
addressing. All variables should be scoped relative
to their current path, if possible. Scoping off the
root is not recommended—this limits the portability
of the code. Use "_parent" or "this"
instead. If you must use absolute addressing to the
main timeline of the movie, use an accessor in the main
timeline. This allows for easy modification of "this"
parameter. To create a convenient reference to the main
timeline of a movie, you should add this line to your
movie's main timeline:
//(substitute the name of your application for "myApp")
_global.myAppMain = this;
You can then use _global.myAppMain.someFunction to refer
to functions on the main timeline. This allows your
movie clip structure to change. |
|
· |
"_root"
vs. "_global". Know the difference between
"_global" and "_root". "_root"
is unique for each loaded movie. "_global"
applies to all movies that exist within a movie. Generally,
the use of "_global" is desired. |
|
· |
ActionScript coding standards by Mike Williams
(in PDF format, 716K). This is a useful document which
contains more scripting recommendations and best practices. |
|
| |
Macromedia Flash
Communication Server MX: Application coding guidelines
This article is not intended to start a heated debate
on coding styles. These suggestions are merely recommendations
that may make it easier when designing the structure of an
application. If a series of applications contain familiar
structures, it makes it easier for a whole team of developers
to understand and modify the applications as needed. Consider
the following guidelines when you are developing:
|
|
· |
How do you
inherit from a class and still call the constructor
of the parent class? The following code example demonstrates
this:
/////////////////////////////////////
//
// How to Inherit from a class (sample)
//
/////////////////////////////////////
function PlayStream(nc) {
// call NetStream constructor
//
note! super only works with client side programming,
so
// calling the constructor of
the parent class is not possible
// with server side scripting!
super(NC);
// set the buffer
time
this.setBufferTime(this.initBufferTime);
// save the reference to the NetConnection
object
this.nc = NC;
}
// inherit from the NetStream object
// set the prototype to be NetStream
PlayStream.prototype = new NetStream();
// the rest of the new class definition goes here |
|
· |
When
does the instance of the super class get created when
you inherit from another class? The super class gets
created whenever you access any methods of the super
class. So, in the example above the super class gets
created in the constructor of the inheriting class.
Note: Server-side scripting has no notion
of the super class, so the super object never gets
created. In most situations, this does not matter.
It does matter if you inherit from a class which has
native data structures created whenever that class
is instantiated. For this reason, it is not recommend
to inherit from predefined Flash Communication server-side
classes. |
|
· |
When initializing
default properties for a class, try not to do it in
the constructor. It is much better to initialize these
values during class definition via the prototype, as
follows:
// set some default property values
PlayStream.prototype.initBufferTime = 10;
PlayStream.prototype.waitingForBufferEmpty = false;
PlayStream.prototype.timeTotalShadow = 0;
playStream.prototype.bufferTotalShadow = 0;
In general, any value which doesn't need to be initialized
in the constructor should not be initialized there.
Ex. function MyFavoriteClass()
{
this.init();
}
MyFavoriteClass.prototype.init = function() {
this.x = 0;
this.y = 0;
this.z = 0;
};
If the only time the above init() is called is in the
constructor, then the code above should be changed to
the following: function
MyFavoriteClass() {
// no init here
}
MyFavoriteClass.prototype.x = 0;
MyFavoriteClass.prototype.y = 0;
MyFavoriteClass.prototype.z = 0; |
|
· |
The rules
for initclip are as follows: If you want users
to be able to inherit from your component class, you
need to provide and order for the initclip.
Ex.
#initclip 1
function FRadioButtonClass() {
this.init();
}
FRadioButtonClass.prototype = new FUIComponentClass();
.
.
.
#endinitclip
When you provide order for the initclip, it lets the
player know which initclip to execute first. You want
to make sure that the object which you are inheriting
from gets defined before you inherit from it. So if
your component inherits from a component which has
an "#initclip 4" in it's definition, your
component then must issue an "#initclip 5"
or above. There is no need to worry about what range
your initclip will occupy. The only thing to make
sure is that the initclip of your component has a
higher order (number following the "initclip"
statement) then the component you are inheriting from. |
|
· |
Override
onStatus for all of Macromedia Flash Communication Server
MX objects. This should be one of the first things you
do, even if your application does not need to do anything
in the onStatus callback. One strategy involves overriding
the onStatus when you start writing the application,
as shown below: ex. //+
// Trace all the status info
//-
function traceStatus(info) {
trace("code is: "
+ info.code);
trace("level is: "
+ info.level);
}
NetConnection.prototype.onStatus = traceStatus;
NetStream.prototype.onStatus = traceStatus;
SharedObject.prototype.onStatus = traceStatus;
Once you need to actually override the callback for
a specific purpose you can delete the code above, but
at least in the meantime you will always see all of
the messages related to the communication server application.
This will save a considerable amount of debugging time
when you are getting started. |
|
· |
The style
of the Macromedia Flash code beautifier is the preferred
coding style. The page real-estate is valuable and this
style uses the least amount of vertical space and gives
the most information. If you feel strongly about your
style we are not insisting that it must be changed.
We realize that this could be a very serious obstacle
for many in switching their curly parentheses location.
We are simply suggesting a common style for all. |
|
· |
If you are
inheriting someone's project, stick with the coding
style which is already in place! ex.
// if the style is
if (condition)
{
statements
}
else
{
statements
}
// don't switch to this style
// in the middle of the project
if ( condition ) {
statements
} else {
statements
} |
|
· |
Use the right
suffix when declaring variables which are Macromedia
Flash Communication Server MX objects as follows: |
| |
Supported Flash
Communication Server suffix strings for code completion
(client side scripting) |
| Object
Type |
Suffix
String |
Var
Example |
Camera |
_cam
cam
|
some_cam
cam |
Video |
_video
video
|
some_video
video |
LocalConnection |
_lc
lc
|
some_lc
lc |
Microphone |
_mic
mic
|
some_mic
mic |
NetConnection |
_nc
NC
|
some_nc
NC |
NetStream |
_ns
ns
|
some_ns
Ns |
SharedObject |
_so
so
|
some_so
so |
|
| |
|
| |
Supported Flash
Communication Server suffix strings for code completion
(server-side scripting) |
| Object
Type |
Suffix
String |
Var
Example |
NetConnection |
_nc
NC
|
some_nc
NC |
Stream |
_stream
stream
|
some_stream
stream |
| Client |
_client
client |
some_client
client |
| Application (this a singleton
object which is globally pointed to by the application
variable) |
application |
application |
SharedObject |
_so
so
|
some_so
so |
|
|
|
ex.
main_nc = new NetConnection();
play_ns = new NetStream(main_nc); |
|
· |
In C++ it
is common practice to precede the names of member variables
of a Class with an "m_".
"C++"
ex.:
class Person {
public:
int m_height;
int m_age;
int m_weight;
};
Person::SetInfo(int height, int age, int weight)
{
m_height = height;
m_age = age;
m_weight = weight;
}
This practice in C++ makes sense since, when reading
code, many developers key of "m_" to assume
scope. In ActionScript (or JavaScript) this practice
would be redundant. You must always use the "this"
specifier in the methods of a Class and so "m_"
prefix is just not needed. "JavaScript"
ex.:
function Person() {
}
Person.prototype.height = 0;
Person.prototype.age = 0;
Person.prototype.weight = 0;
Person.prototype.setInfo = function(height, age, weight)
{
this.height = height;
this.age = age;
this.weight = weight;
} |
|
· |
Know the
difference when marking a slot of a shared object dirty
on the client vs. the server. Let's say that the shared
object data property is list of objects of type Point.
And let's assume you want to change the value of slot
"23" to x = 46 and y = 78. The following code
examples illustrate how to accomplish this task on the
client and on the server.
ex. client
my_so.data[23].x
= 43;
my_so.data[23].y = 78;
ex. server
var tmp = my_so.getProperty("23");
tmp.x = 43;
tmp.y = 78;
my_so.setProperty("23", tmp); |
|
· |
The preferred
way to iterate through an unordered list is shown below:
ex.
for (i in objOrArray)
{
// do something with objOrArray[i]
}
This style allows flexibility, because it doesn't matter
whether a list or an object is being referenced. It
could be either an array or an object. |
|
· |
Make sure
you understand the language differences between ActionScript
on the client and ActionScript on the server. Here is
a quick list of some of the most common differences:
|
|
|
|
Feature/key word |
client side scripting |
server side scripting |
| _global
(object) |
yes |
no
|
| System
(object) |
yes |
no |
| super |
yes |
no |
| Object.registerClass() |
yes |
no (use)
application.registerClass() |
| case
sensitivity |
no |
yes |
accessing
an undefined variable |
yes |
will cause an assert. You must declare the
variable first before checking its value
i.e.,
var foo;
.
.
if (foo == undefined) |
| function
forward referencing style1
ex.
foo();
function foo() {
}
|
yes |
yes |
| try
catch blocks |
no |
yes |
|
|
· |
How does
one chain onSync, onStatus, etc. without destroying
the previous callback? This code example provides an
answer to that question:
ex.
SharedObject.prototype.attachOnSync
= function(func) {
if (typeof(func) != "function")
return;
if (this.onSync == undefined)
{
this.onSync
= function(list) {
for
(i in this.onSyncList) {
this.onSyncList[i](list);
}
}
this.onSyncList
= new Array();
}
this.onSyncList.push(func);
}
.
.
.
function myCallback(list) {
// yada, yada, yada
}
my_so.attachOnSync(myCallBack); |
|
· |
How can
you check for undefined variables on the client and
on the server? Try the following:
//+
// on the client
//-
if (foo == undefined) {
// do something here
}
//+
// on the server you must use the method below if
you
// don't and the type is truly undefined the server
script
// will throw an exception if you use the style above
//-
if (typeof(foo) == "undefined") {
// do something here
}
|
|
| |
| Conclusion
This documents summarizes good practices when creating Macromedia
Flash and Macromedia Flash Communication Server MX applications.
The idea is to avoid common pitfalls which could lead you
into trouble while creating sophisticated applications.
Everything here is a suggestion. There are many styles and
many philosophies which can be followed during application
development. What is suggested here is the general practice
of many Flash developers. Hopefully, there are some useful
suggestions and hints here that you can practice in your
own Macromedia Flash and Macromedia Flash Communication
Server MX application development. |
| |
|
| About
the author
Slavik Lozben is a principal engineer on the Flash Communication
Server team. He was involved in the design and implementation
of many of the features in the product. Slavik joined Macromedia
in January of 1995. He originally worked on the Director
product line. When Macromedia bought what is now known as
Flash, he saw a tremendous opportunity and joined Robert
Tatsumi and Jon Gay, the creators of Flash. He has been
on the Flash team ever since. |
|
|
|