Advanced Function Work

In this post I’m going to show you a few more advanced features of AS3 functions. I think you’ll find they certainly help, at least when it comes to coding an API for the general public.

…rest Parameter

The rest parameter is cool little parameter type in AS3. It allows for varying sizes of parameter lists to be passed into functions. Let’s look at a quick example:

public function foo(bar:String, foobar:Object, ...rest):void

In this example, we declare function called foo, which has two defined parameters called bar and foobar, and then as the last parameter we have this thing called …rest. As you can tell, …rest is the rest parameter. The rest parameter is declared by three ellipses or dots (…) and then followed by the parameter’s name. In this case I’ve named it rest, but you could name whatever you like. For example:

public function foo(bar:String, foobar:Object, ...someBigListOfWhoKnowsWhat):void

What does this look like for the person who’s calling the function? Let’s take a look:

foo("bar", {foobar: null}, "some", "Big", "List", "Of", "Strings"):void

As you can see, when we call this function we pass in the two defined parameters, and then comes a big long list of parameters that we didn’t define; this is how the rest parameter works, the user can put in as many parameters as they like. It’s important to note, that the user can also pass in parameters of any type, so you’ll have to do some checking if you want the parameters to be of a certain type.

Now we’ll get onto how you can actually access these parameters passed in. When the function actually starts executing it’s statements, the rest parameter has been converted into an array. So we can access the parameters like this:

public function foo(bar:String, foobar:Object, ...otherParams):void {
trace(otherParams.length);
trace(otherParams[0]);
trace(otherParams.shift());
otherParams.unshift("tom");
}

As you can see, we can perform various array methods on it, access the length property, and access the elements in the array. We could also do a for each or for loop on the array, and so on. But what if we need to pass these parameters on to another function, expecting a rest parameter (not an array) itself? That’s what we’ll discuss next.

Function.apply()

When you define a function, you are creating a Function object. The object itself has a number of handy methods. One of those methods we are going to talk about today, and that it the apply() method.

The apply method allows you to call a function, but pass in the parameters needed as an array. Let’s write some setup code:

public function foo(bar:String, ...otherParams):void {
// bar is a string we need to do some processing on
var bar2:String = bar.replace(/\$\d/, someArray[0]);
}
 
public function bar(foo:String, ...otherParams):void {
// some code to do something with these parameters
}

Now what we need to do is when someone calls foo, we want to do some processing on the bar string as seen in foo(), and then pass on the processed string and all the parameters the …otherParams rest parameter to bar() and return whatever bar() returns. How do we that when, inside the actual function, otherParams is an array (meaning we can’t just go

return bar(bar2, otherParams);

). This is where apply() comes in:

public function foo(bar:String, ...otherParams):void {
// bar is a string we need to do some processing on
var bar2:String = bar.replace(/\$\d/, someArray[0]);
var applyParams:Array = otherParams;
applyParams.unshift(bar2);
return bar.apply(this, applyParams);
}

So what we’re doing that’s different is, creating an array called applyParams; this is the array of parameters to pass to apply(). Then we are adding the processed string (bar2) to the front of the applyParams array. Finally, we are calling the apply method of the bar object (which is a Function), passing in this (this object) and the applyParams array and returning the returned value. The apply method will use the array as the list of parameters for the function and everything will work smoothly. But why do need to pass in the “this” reference? The first parameter of apply, (so far as I understand it) is what object to point to wherever “this” is referred to in the function. Therefore, be careful with that one and take into account where the function is located.

Anyway, that wraps up this post, hope you learnt a thing or two about functions. I could say more, but I’ll leave it at that. Please feel free to post your thoughts below.

Problems with Tween and Using TweenLite

Have you had trouble with Adobe’s Tween class? (Used for so called “easy” ActionScript animation of display objects) I sure have, so I thought I’d write a post about it. When I was first taught how to animate with ActionScript, I had many a lock up and stutter from the Tween class. For awhile I was quite annoyed, seeing the benefit of animation using ActionScript but thinking that it was totally unreliable. Now there are a number of methods to fix the problems with Tween, using Dictionaries, new objects and so on; all of which seemed tedious and time consuming. Thankfully, I found a better solution, third party tweening engines! I’m going to tell you about what I think is the best one, TweenLite.

TweenLite (and the Greensock Tweening Platform) is simple, powerful, fast and reliable. Greensock has many awesome classes, generously available for free, all of which are (so far as I understand) maintained by one person. You can get them at http://www.greensock.com/

I’ll just go through a few features with you now. First of all the TweenLite object has two main methods, to() and from(). With these you can change and object’s properties, from their current value to a new value at a certain rate. from() works similarly; it sets the properties of an object to what you specify, and then moves those properties back to what they were. So you can tween object’s in both directions.

Let’s experiment with to():

import com.greensock.TweenLite;
TweenLite.to(object, 1.25, { x: 20, y: 45, alpha: .8, customProperty: 20.36 });

The first parameter is the object you want to perform a tween on. The second is the amount of time you want the tween to take. And the third is an object literal of properties you want to change. In this case these properties will be moved to the values specified. TweenLite can modify any numerical property of an object, making some really powerful stuff possible.

Next I’ll talk about a few of the special properties, they are: onStart, onComplete, ease, and delay. Here’s a definition of them:

  • onStart – A function that should be called when the tween begins (when its currentTime is at 0 and changes to some other value which can happen more than once if the tween is restarted multiple times).
  • onComplete – A function that should be called when the tween has finished
  • ease – Use any standard easing equation to control the rate of change. For example, Elastic.easeOut. The Default is Quad.easeOut.
  • delay – Amount of delay in seconds (or frames for frames-based tweens) before the tween should begin.

Let’s try and use the ease property first:

import com.greensock.TweenLite;
import com.greensock.easing.*;

TweenLite.to(object, 1.25, { x: 20, y: 45, alpha: .8, customProperty: 20.36, ease: Sine.easeOut });

Note the extra import, we must import the easing classes to be used with the tween. You can use all the standard easing equations, and a few extras to my knowledge.

Now for the rest of those properties:

import com.greensock.TweenLite;

TweenLite.to(object, 1.25, { x: 20, y: 45, alpha: .8, customProperty: 20.36,
   ease: Sine.easeOut,
   onStart: startFunction,
   onComplete: completeFunction,
   delay: 3
});

So this tween will trigger startFunction() when it starts, completeFunction() when it ends, and will wait 3 seconds before starting.

That’s just the tip of the iceberg, but the engine has great documentation, so go to http://www.greensock.com/ and check it out. The purpose of this post was not to rewrite the documentation, but to get your feet wet and show you a better way to tweening.

Using the AMFPHPConnection class

In this post I’ll be talking about a class I’ve made called AMFPHPConnection that extends Flash’s NetConnection object. This class eases and enhances the process of using AMFPHP for Flash remoting. But before we begin, just a few notes: I’m not the usual author, and you’ll need to know how to use AMFPHP the normal way, or you may not get some of the terminology. If you want to learn how to use it, I have a series on my YouTube channel for that purpose, go here to watch it: http://www.youtube.com/user/BlackBulletIV#grid/user/CAD2DAE46A04939D

First go and download the class from here: http://www.nova-fusion.com/cms/FileFolder/AMFPHPConnection.zip

This zip file contains the minimized class in it’s package folders: com/novafusion/net/AMFPHPConnection.as. It also contains readable version of the class, which has documentation, comments and more whitespace; it is: AMFPHPConnectionReadable.as. If you actually want to use this class instead, rename it to AMFPHPConnection.as and place it in the proper package folders. The zip file also contains package details similar to what I’m talking about now, and instructions similar to what I’m going to be talking about below. Now let’s get onto how to use it.

Setup

To get started, import the class:

import com.novafusion.net.AMFPHPConnection;

Next create a new instance, you can call the variable name whatever you like but I’ll go with connection:

var connection:AMFPHPConnection = new AMFPHPConnection("http://localhost/amfphp/gateway.php");

When you create a new instance, you are expected to pass in one parameter, the path to your AMFPHP gateway.php file. When you create the instance the class will automatically set up a connection and a responder for your function calls. If you would like to change the gateway location at any point do this:

connection.gateway = "http://www.some-other-server.com/amfphp/gateway.php";

This will set the gateway location in the class and reconnect to that server. Access the path to the current gateway this way:

connection.gateway

Quick Service Referencing

Quick service referencing helps a lot in speeding things up and reducing the amount of code you have to right. If you have a service you use a lot in your code, the connection class can store it for you and cut down how much you have to type to reference it. Examples of referencing strings are:

"FlashPHPTest"; // just a class name, but this could be a folder name
"UsingAMFPHP.TalkBack"; // folder and a class inside it
"UsingAMFPHP.TalkBack.put_together"; // folder, a class inside it, and a method inside the class
"FlashPHP" // part of a class name (could be folder or method name)

You can basically store any string in them, and reference it quickly when calling a service. You could use each of these reference strings in calls like this:

"$1.spitBack"; // just a class name, but this could be a folder name
"$2.put_together"; // folder and a class inside it
"$3"; // folder, a class inside it, and a method inside the class
"$4Test.spitBack" // part of a class name (could be folder or method name)

You use your references with a dollar sign and then it’s number (which is assigned to it in the order you add them to the class). As you can see this will greatly reduce what you have to write in your code.

You can add service references in two ways. The first is to add them in when constructing the class:

var connection:AMFPHPConnection = new AMFPHPConnection("http://localhost/amfphp/gateway.php", "FlashPHPTest", "UsingAMFPHP.TalkBack");

The second way is to add them in with a method provided:

connection.addServices("FlashPHPTest", "UsingAMFPHP.TalkBack");

You can add as many as you like at one time, and use the method as many times as you like. You can also remove service references like this:

connection.removeServices("FlashPHPTest", "UsingAMFPHP.TalkBack");

It’s not recommended that you remove service references, as it might generate confusion as to the order in which to reference them afterwards (just more for you to keep track of).

Calling Services

To call a service, use this method and pass in your service and parameters (not the responder! That’s taken care of for you):

connection.talk("SomeService.someMethod", "Some parameter", "Another parameter");

The function is called talk because of confliction with the NetConnection object’s call method. However you can still use that method, like this:

connection.call("SomeService.someMethod", null, "Some parameter", "Another parameter");

You can pass in the responder either as null (the object’s responder object will be used instead, which is what you want), use connection.responder (replace connection with your instance name), or pass in your own custom responder (note that result and fault listeners won’t work).

You can use quick service referencing in your calls like this:

connection.talk("$1.spitBack", "Hello world!");

Just use strings in the style shown in the quick service referencing section and all will be well.

Result and Fault Listeners/Handlers

We need to see up some listener/handler functions to respond to results and faults from AMFPHP:

function onResult(event:Event):void {
// do whatever
trace(connection.result);
}
function onFault(event:Event):void {
// do whatever
trace(connection.fault);
}

Notice that instead of receiving objects they actually receive plain event objects; that’s because they’re triggered by custom event listeners. You access the last result object with connection.result (replace connection with your instance name) and the last fault with connection.fault (replace connection with your instance name). Now how do we add the listeners for these functions? Here’s how:

connection.setListeners(onResult, onFault);

Just pass in the result function and the fault function and they’ll be triggered for their respective events. Now you don’t have to set either one, if you want to set the fault handler but leave the result handler as it is just leave the onResult function as null. Now be careful about these handlers, when you set them like this they become the default handlers for all calls. One way to get around this is to remove the listeners in the on result or on fault functions, using this:

connection.removeListeners();

You could do that, but there’s a better way to do it. Set the third parameter of setListeners() to true; this will make these listeners only last for one call, and on the next result or fault they will be removed. Here’s how:

connection.setListeners(onResult, onFault, true);

You could also add listeners the harder way like this:

connection.addEventListener(AMFPHPConnection.RESULT, onResult); // For results
connection.addEventListener(AMFPHPConnection.FAULT, onFault); // For faults

And of course to remove them you just use them same code, just change the function to removeEventListener().

Conclusion

Hope that helps! Here’s a sample application to give you some perspective on how this class lessens your code when using AMFPHP:

import com.novafusion.net.AMFPHPConnection;

var connection:AMFPHPConnection = new AMFPHPConnection("http://localhost/amfphp/gateway.php", "UsingAMFPHP.TalkBack", "FlashPHPTest");

function result(event:Event):void {
trace(connection.result);
}

function fault(event:Event):void {
trace(connection.fault);
}

connection.setListeners(result, fault);
connection.talk("$1.put_together", "tom", "bob");
connection.talk("$2.spitBack", "tom");