Tricks of the Trade

Im going to post little AS tricks here when I think of them, to learn and have here for reference. Off-hand I cant really pull them off of the top of my head, but they come to me when I need them in coding. When that happens Ill come back and post anything thats considerably ‘tricky’ enough to be posted here.

Right now Ill do Daisychaining and callbacks. These I know now because I used them recently :wink:

Daisychaining
Though not the technical term (I dont think - its just what I call it) daisychaining is the act of throwing a bunch of methods on the end of an object (and each other) to have them all called in one line of code. Ex:


objClass = function(name, value){
	this.name = name;
	this.value = value;
};
objClass.prototype.showName = function(){
	trace(this.name);
	return this;
};
objClass.prototype.showValue = function(){
	trace(this.value);
	return this;
};
objInstance = new objClass("cletus",12).showName().showValue();
// outputs "cletus" and "12".

The trick lies in returning the object, this in the prototype functions. Then, when called, the action is executed and the object is returned. When returned, the next method is executed on the returned value which is the object itself.

Chances are you’ve seen this before with the easy version of a string replace: str.split().join(); I used it here on Kirupa in the Gaming battle creating and drawing objects in on the screen (and instantly adding onEnterFrame events to dynamically created objects).

Callbacks
These are functions associated with an event. When the event is triggered, the callback function is run in responce. Setting an onMouseDown function is setting a callback function. However, you can also incorporate such functions into your own code allowing you to set a temporary set of instructions to be run at a later time. A simple example of this can be implemented in a tweened or multi-framed transition. Lets say you have about 6 or so pages of content in your movie and a small animation leading up to and leading out of each page. In moving from page to page you have to not just goto the new page but play out of the current. What you could do is set your buttons in each page to play() the exit animation and set up a callback function which is to be run at the end of that animation. Example:


// button
on(release){
	action = function(){
		_root.gotoAndPlay("page2_label");
	};
	play();
};
// last frame
action();

Now certainly, in that simple example you could just set a variable and throw it in a gotoAndPlay at the end of the animation, but this allows for many actions to occur which can be similar or vastly different (if anything at all) from any other set callback functions. I used it here on Kirupa in the XML menu example using a callback menu to open the next menu section after closing the current.

Function Appending (MX)
One common problem which may arise within your coding is the addition of actions within an onEnterFrame event (or any event for that matter). Once you set an event like onEnterFrame, if you ever try to add on a function call using onEnterFrame = you will not append the call to the current action but replace it, therefore preventing the original from being run again. To get around this, you can do the following:


// assign
this.onEnterFrame = function1;

// append
oldEnterFrame = this.onEnterFrame;
this.onEnterFrame = function(){
	oldEnterFrame();
	function2();
};

So what happens is the old onEnterFrame is saved in the variable oldEnterFrame and the new onEnterFrame is set to equal a function running that AND the new function you want to add to the event, in this case, function2. So the old onEnterFrame runs, then the new function all within the next onEnterFrame call. And really, this can be done everytime you assign an onEnterFrame action (assuming you want to add to whats there) even if theres nothing there to begin with because the oldEnterFrame call, if no onEnterFrame has yet been set, will just be null. However, this is a little bulky and would be a pain to continue using in the manner. Instead, lets write a function that will do that for us. Luckily MX allows Function ‘object’ prototypes which makes this job a lot easier. We can write two versions of whats above, one to insert the new function before the old function, and one to insert the new function after the old function. If you have one funcion relying on results from another, you’d want to be able to control which one gets called first on an onEnterFrame…


// prototype assignment
Function.prototype.addAfter = function(newFunc){
	var oldFunc = this;
	return function(){
		oldFunc();
		newFunc();
	};
};
Function.prototype.addBefore = function(newFunc){
	var oldFunc = this;
	return function(){
		newFunc();
		oldFunc();
	};
};

// whenever needed use in the following manner:
this.onEnterFrame = function1;
this.onEnterFrame = this.onEnterFrame.addBefore(function2);

First onEnterFrame is assigned function1, then its assined the return of the addBefore call which gives a new function with this.onEnterFrame and the passed function2 called together.

First thing: don’t ‘daisychain’ like that.

Returning “this” as a property will return the entire object. This method will cause infinie recursion if you are not extremely careful with your code - and a worse practice if you are coding complex components with various levels of initialization.

Best method to add extra properties onto an object for them to be called is to develop a routine that calls a list of objects in that object which need to get called … basically a function queue. This can be emulated with function arrays. All you need to do is to push the function on the end of the array, or splice/join in different areas to change the order of execution.

Second: your callback method is not good either. It is bad practice to define a function inside a function, in any language. If you want to design a callback, program a callback function for your component. Using arguments.callee will help with complicated interaction when you don’t know what callback function to execute if you are developing a generic class.

That’s my first post. I’m checking out the other stuff now… :slight_smile:

TIP: Dont animate on the main timeline. Instead do everything within movieclips. This makes the movie more portable … helps in Flash 5 where you can have MX like events. It also gives you more control in handling the project on a whole allowing to easily scale/reposition etc.

True & False as Numbers (Key movement)
You probably already know that you can evaluate numbers as being either true or false with 0 being false and any non-zero number being true. What you can also do is use true and false themselves as numbers as well. In terms of value, true is 1 and false, 0 - which makes sense since in terms of number value 1 is evaluated to be true and 0 to be false. So true and false can then be used in mathematical calculations, ie. true * 5 = 5, false + 10 = 10 etc. This can save you some time/code if you had something like the following:


// is a member is a true or false boolean
if (isAMember){
	dailyAllowance = 10;
}else{
	dailyAllowance = 0;
}

// can be shortened to
dailyAllowance = 10 * isAMember;

One of the more applicable uses of this, I think, is in Key controlled movement. When dealing with key movement you commonly run accross multiple if statements of if Key.UP this, if Key.DOWN this, etc. This can be reduced to just a couple of lines


my_mc.speed = 5;
my_mc.onEnterFrame = function(){
	this._x += (Key.isDown(Key.RIGHT) - Key.isDown(Key.LEFT)) * this.speed;
	this._y += (Key.isDown(Key.DOWN) - Key.isDown(Key.UP)) * this.speed;
}

since Key.isDown returs true or false, you get more or less 1 or 0. That gives you, from that equation, either -1, 0 or 1, all which will give you a distance of movement when multiplied by a clips ‘speed’.

PS. these are ‘tricks’ not ‘good programming practices’ :wink:

*Originally posted by senocular *
Function Appending (MX)

Heh. Originally posted as an idea on Flashcoders, many moons ago. :slight_smile:

Anyhow, appending functions like this can work sometimes, but can cause issues later on. If the code is ever run without initialization (ie, run again but not initialized with the =function1), you will be appending multiple events that are identical to the enterFrame event.

Best practice is to, again, use function tables and have your onEnterFrame() event be the caller for the table listing. This way, you have complete control over order of execution, removal or joining of new functions, or additing of functions at the beginning or end of the chain.

Luckily MX allows Function ‘object’ prototypes which makes this job a lot easier. We can write two versions of whats above, one to insert the new function before the old function, and one to insert the new function after the old function. If you have one funcion relying on results from another, you’d want to be able to control which one gets called first on an onEnterFrame…

You might want to be aware that everything in MX is an object. Actionscript, like Javascript is an object-based language (not class based like C/C++). Note that I said “object-based” and not “object-oriented,” as those terms are not really interchangeable.

Functions and everything else are already objects. This is why I can parse _global as an array (because it is an array) and why I can return methods of a function because those methods are more objects of the function object (objects of an object).

This functionality allows us to do some very interesting things with the language, though for sake of clean coding and portability, many of those things are not very good ways of approaching the situation (as this and my last post point out).

cheers.

True & False as Numbers (Key movement)

I’d think it’s safe to say that any programmer should know that true == 1 and false == 0, a fundamental aspect of coding … and one which can be useful at times.


// can be shortened to
dailyAllowance = 10 * isAMember;

Yea, you could do that. But it’s not legible. No one is going to notice that if they see it in your code. It works, but it’s not really good practice, as you said yourself … :slight_smile:

Better, with one line:

dailyAllowance = isAMember ? 10 : 0;

This queries the isAMember, if true it evaluates the first element before the semi-colon, else it evaluates the latter element. This is better because it can be compounded with functions easily, and still keep the code simple and easier to understand (provided the reader knows the semantics of the language).

dailyAllowance = isAMember ? getAllowance() : 0;

… food for thought.

well Ive lost all interest in posting anything else here :-\

*Originally posted by senocular *
**well Ive lost all interest in posting anything else here :-\ **

Oh, come on now. Your help is definitely appreciated. I just wanted to clarify your posts because you are posting on more complicated subjects … things that are routinely discussed on lists like Flashcoders. As with all things, there are many different ways of approaching a concept. In the case of daisychaining and callbacks, there are already standard and accepted methods in OO. Deviating from those standards can cause confusion to someone that’s getting deeply involved with OO design.

The biggest headaches can come when you get into full-scale development of large component and applications in MX is the deviation from standard coding practices (or poor practices).

I think your tips are wonderful, they just needed to be reworked.

Don’t stop dude … keep it up. This is a productive discussion and I learned a few new approaches to the same idea. Sure, there can be better ways to do something … but sometimes all that matters is that something works. Know what I’m sayin?

peace.

Best of Kirupa definitely, but I left a redirect in the actionscript section.

Very interesting :slight_smile: [SIZE=1]And Sen, it’s good to exchange points of view sometimes, no? [/SIZE]

Let this be the thread for the future AS-tricked, shall we?

I’ve just found this at as.org, in a post by FlashGuru (my God he’s good :crazy: ):

Array duplication made easy

To make a duplicate of an array proves more difficult than it seems. For instance, if you try this piece of code:

a=[1,2,3];
b=a;
a.pop();
trace ("a="+a);
trace ("b="+b);

it will return

a=1,2
b=1,2
even though you’ve applied the method Array.pop on a only. b is a reference to a, an alias if you prefer, not a copy.

So here’s a little prototype to solve the problem. All you have to do is use the Array.splice method, with no parameter to keep the whole array.

// Credits: FlashGuru
Array.prototype.copy=function(){
        return this.slice();
};
tester=[1,2,3,4];
tester2=tester.copy();

That’s a good snipped of code if you want to have a completely separate function for doing that - but it’s also identical to re-referenceing an already defined function in AS.

Try:

a = [1,2,3];
b = a.slice();

Or:
a = [1,2,3];
b = a.concat();

Or:
a = [1,2,3];
b = a.join();

These will execute much faster if you’ve got huge arrays to deal with (say 256x256).

peace.

Theres a place for comprehension and theres a place for speed. Chances are, for basic array manipulation you arent going to have to worry about speed in which case the function overhead for that definition is negligble. Seeing copy being used with an array will let you know right away that you are copying the array, slice doesnt indicate that as clearly. Besides, if it was speed you are after youd give the function a single character name.

Also know you can use this:

Array.prototype.copy = Array.prototype.slice;

It doesn’t call slice within copy but rather just gives another name for it.

tester=[1,2,3,4];
tester2=tester.copy();
trace(tester2); // 1,2,3,4

*Originally posted by senocular *
**Theres a place for comprehension and theres a place for speed.

Also know you can use this:

Array.prototype.copy = Array.prototype.slice;

It doesn’t call slice within copy but rather just gives another name for it.

tester=[1,2,3,4];
tester2=tester.copy();
trace(tester2); // 1,2,3,4

**

Good job!

But speed does have it’s place. I wrote a Mandlebrot explorer that renders a 400x200 sized image to the screen using lineTo methods. To calculate the fractal and escape value for each pixel about 400 lines are called, about 100 times (per pixel!). Actionscript execution is very fast, but the number of lines of AS called here get way out of hand …

80000 * 400 * 100
3.2e9 (that’s 3.2 billion)

If I can save a few milliseoncds by not creating a reference to another function (which has to be checked each time it’s called), then I’m a happy camper.

But, I tend to do things out of the norm sometimes … :slight_smile:

[out of the subject]You scared the **** out of me when I saw you answered my post, jbradley :stuck_out_tongue:
Anyway, thank you both, that’s very interesting, and will definitely be included in the official AS trick, if I ever get to write it :).

And jb, can I see that Mandelbrot of yours? I tried to do one for the Bit-contest some time ago, but another French beat me to it :evil: [/out of the subject]

I like this thread :beam:

Ok, I couldn’t find my larger version so I’m uploading a smaller and more compact one. I decreased the code significantly in this version since it’s just supposed to show the idea, instead of being a full fractal explorer (like my other version), where you can view different types of fractals. This is just the Mandlebrot.

The settings are as follows:

Smoothness
The higher the number the more accurate a picture of the escape velocity of any point inside or outside the Mandlebrot fractal set. When the function is calculated over and over, a certain value approaches infinity. The coloring of the fractal, called domain coloring, maps this speed of infinite approach. The higher the smoothness the more accuracte the calculations.

Trace Size
‘Pixels’ on the screen are drawn with lines. Line size can range from 1x1 to 5x5 (one number provided, the size of the line 'square). At 5 there’s a pixel line that gets skipped … oh well. Stick with 4 or lower, though 5 can be cool to look at, and with a smoothness of around 50 renders very fast.

Stop
Just stop the current rendering. Very processor intensive application, so the clicking may take a second to register in the application.

Resume
Start from the last place you were in the rendering. You can change the trace size during rendering, but it messes everything up.

Redraw
Redraw the screen. There’s a problem sometimes when you click Render with the screen not being cleared. This will fix that if you change line size and the application starts slowing down (lines over lines). Just click this and it should clear and dump the old drawing. If clicked during a trace, it’ll clear and start where the trace left off … so let the rendering finish.

Render
Initializes everything. Gotta click this to get anything to happen really. :slight_smile:

Clicking in the screen will zoom the view. Zoom is inifinite, and approximately 10x each time you click. So, you can zoom way way in to the set. Sometimes a click outside the view will register (don’t know why and didn’t care to fix it in this 10 min. compacted version). Tread lightly but have fun exploring.

Enjoy.

*Originally posted by jbradley *
**First thing: don’t ‘daisychain’ like that.

Returning “this” as a property will return the entire object. This method will cause infinie recursion if you are not extremely careful with your code **

thought Id ask…

can you give an example of this please jbradley?

thanks

couldnt think of one off the top of my head when you posted, came to mind again today and thought Id throw it out there.

In Flash AS Editing (MX)

Code Formatting/Indention
There are a couple of new ways to help you in editing Actionscript in Flash MX (expert mode). One feature is Auto-indent which automatically indents your script as you type. Along with this you have Auto-format (ctrl+shift+F) which take a script and correctly indent the lines for you appropriately if they arent already. This is good for when you’ve copied and pasted a large block of code off of the internet (like this board) or some other source which, then, did not have porper formatting. Auto-format will approriately format it for you making it easier to read. One other method of formatting (indenting text) which surprisingly flashguru only recently figured out, is Selection indenting. Given any number of lines of selected text, when hitting the tab key, those lines will indent by one tab stop outward. This is useful for encasing a large block of code in, say, an ‘if’ statement, with the ability then to select that block and properly indent it. Shift-tab will reverse indent.

Code Duplication
One way to save on typing is code duplication. This especially for things such as onClipEvents where you may have a few events on a single movieclip (and therefore a single page of code) and you may find it easier to, instead of retyping "onClipEvent(){} for each block, just duplicating the first one over again for reuse. This is nothing new in the world of computers - duplication but it may be something which you havent mastered yet and is worth using if you’re finding yourself coding a lot :wink: There are 2 basic ways of duplication. One is copy-and-pasting. I use the CPP method - or Copy Paste Paste. What this is, is selecting code to copy and then, pasting twice immediately thereafter. Once to replace the currently selected text, and another to create the duplicate text. Essentially this is the same as deselecting and pasting once, but this just does it with a little more ease because it doesnt require the use of the mouse. Should you need to position the new text somewhere else, being that its selected, you can just click and drag it to a new location. The other way is Duplication through dragging. In Windows the key is ctrl, and macs I believe its command, but when moving selected text with this key down, a copy of that text will be made as opposed to that text being moved. This however, only works when the cursor is moved outside of the selected text so when you need duplicate some code beneath the original, CPP might be better fit. However, duplicating this way with dragging also lets you duplicate text while maintaining the contents of your clipboard which you may want for later use. This technique is probbaly best used on variable names where to reuse/copy that variable, simply find a previous instance of it, double click and ctrl+drag it to the new location to make a copy. At times, this may save you some typing and some time.

Code Re-arrangement
As noted before, you can select code and move it around with your mouse by dragging. This can be good to change the orders of your script for whatever purposes are necessary. In doing this, however, you may want to be sure to also copy the return character of the line above the first line of your selection (selecting from the bottom up). This way you would just need to move your code snippet. at the end of the line which it needs to follow and the line spacing will remain consistent. If this is a little hard to do sometimes, or just as a possibly simpler method of rearrangement, also consider going into normal mode (ctrl+shift+N) to move things around. There, for an if statement for example, you wouldnt have to select the whole statement but just the if line. Moving that will move the entire statement.

For more options, be sure to look in the Actionscript Panels menu in the far right of the panel titlebar if you havent already.

^ along those same lines are the object suffixes (MX). Just in case you didnt know, MX will provide a popup of ‘hints’ for your type code as you are coding. To get these hints for your object instances there are certain naming conventions you can follow that would give you these popup hint boxes. They are all listed in Flash help but Ill throw them here as well.

_mc
MovieClip

_array
Array

_str
String

_btn
Button

_txt
TextField

_fmt
TextFormat

_date
Date

_sound
Sound

_xml
XML

_xmlsocket
XMLSocket

_color
Color

_camera
Camera

_mic
Microphone

_stream
NetStream

_connection
NetConnection

_so
SharedObject

_video
Video

Example: Using myMovieClip_mc as an instance name will give you a list of all the methods associated with movieclips when you type that instance name in the actionsript window.