negush blog

Flash, ActionScript and stuff…

Archive for the ‘Tutorials’ Category

There are situations when you need to create a web application that is part Flash, part HTML, like some handy widget that must reside in an HTML page and that would also have to communicate with it. The next example presents a simple color setting widget made with Flash, which communicates with the web page it is integrated in. Basically the Flash widget contains three slides to set the RGB color value and the composed color is displayed in the HTML page, in a text input control. The user also has the possibility to enter a hexadecimal value of a color in that text input which will set the sliders in the Flash widget to the corresponding values. Flash – HTML communication (actually ActionScript – JavaScript communication) is possible by using the ExternalInterface class within the flash.external package.

The ExternalInterface class was created to replace the older fscommand() function and can be used to call JavaScript functions from ActionScript or call ActionScript functions from JavaScript. It is also able to transmit a return value from the function being called to the code (ActionScript or JavaScript) calling the external function. It is much more flexible than fscommand() since it allows calling any JavaScript function defined in the HTML file with any number of arguments (of various data types), while fscommand() allowed calling a limited number of functions with a single String as argument. Also allows receiving a return value from the JavaScript function call to ActionScript and vice versa.

Calling a JavaScript function from ActionScript is quite easy. All you have to do is call the static call function of the ExternalInterface class:

ExternalInterface.call("myJSFunction");

You can even specify function parameters and receive the return value, like this:

import flash.external.ExternalInterface;
var value:String = ExternalInterface call("myJSFunction", param1, param2, param3);

Of course this means that in the HTML file containing your Flash clip there has to be a JavaScript function defined with the name of “myJSFunction”. In the above example, we presume that the type of the return value of the JavaScript function is a String, but the ExternalInterface class allows receiving other types of values too.

Calling an ActionScript, from within your HTML document using JavaScript is equally easy. All you have to do is get a reference to the Flash object embedded into the HTML document and then call the ActionScript function directly on this object. Of course, this requires that the ActionScript function is defined as a callback function for the JavaScript code, in the main timeline of the Flash clip:

ActionScript code:

ExternalInterface.addCallBack("myASFunction", someASFunction);

JavaScript code:

var flashMovie = window.document.MyFlashWidget;
flashMovie.myASFunction(value);

In this case, the name and id attributes of the Flash object must be set to “MyFlashWidget”. Another requirement for the HTML document is to set the allowScriptAccess attribute of the Flash object to “always”.

“myASFunction” is the function name that the external JavaScript code must call, but the actual name of the ActionScript function is “someASFunction”. This way, external JavaScript code can only have access to the ActionScript code that the developer allows to. Also, in this case, if the ActionScript code must change and the “someASFunction” function is removed, there could be another function passed to the addCallBack method. Thus, it is ensured that “myASFunction” always gets called by JavaScript and that Javascript can actually be oblivious to the changes of the ActionScript code.

One more thing worth mentioning is that it is a good practice to check if the JavaScript code is available for calling, before actually making any calls to it. This way possible errors or malfunctions are avoided in the application:

if (ExternalInterface.available) {
	try {
		ExternalInterface.addCallback("myASFunction ", someASFunction);			}
	catch(e:Error) {
		// Callback function could not be added for various reson.
		// You could treat this situation here.
	}
}

You can download the full example from here. I hope it will help out some of you.

Update: For Internet Explorer you should make sure that you specify your embedded Flash object the id attribute, as mentioned in this post: ExternalInterface.call not working with IE.

April-9-09

Import assets from Library

posted by admin

In ActionScript 2.0 it is quite easy to import movie clips from Library via the MovieClip.attachMovie() function. In ActionScript 3.0 it’s a little bit different. The movie clips (or assets in the Library) don’t have a linkage id anymore. Instead they have class names.

So the way to import a movie clip (or another asset) is to first get a reference to that class specified as class name. This is done using the flash.utils.getDefinitionByName() function. Then instantiate the class and finally add the object to the display list.

Here is a simple example:

1
2
3
4
5
6
7
8
9
import flash.utils.getDefinitionByName;
 
var className:String = "TestClip";
var ClassReference:Class = getDefinitionByName(className) as Class;
var clip:MovieClip = new ClassReference();
 
addChild(clip);
clip.x = 100;
clip.y = 100;

March-29-09

Listing the properties of an object

posted by admin

This is easy for AS2 – you just use a for() statement to go through all the properties the object has:

for (var i in obj) trace(i+" = "+obj[i]);

There would be the property names listed in the Output panel along with their values.

But for AS3, it seems that this is not always working. You would use that for() statement but not all the properties would be listed. It happened to me quite a few times. So, how can you display all the properties of an object ? Well, ActionSscript 3.0 has a useful function called describeType(). It is located in the flash.utils package. It must receive the target object (or even a class name) as argument and it returns a XML object containing the properties and methods of that object/class. Pretty neat, huh ?

Now, I’ve played around with it a little and it seems that there’s a catch to it. If your target object is an instance of a dynamic class (it allows you to add new properties dynamically), the describeType() function will only display the properties and methods listed in the class, without the extra properties you might have added. So, practically the final solution might be the use of both the for() loop and the describeType() function, especially if you want to make sure that all of the properties are listed and you’re not sure whether the object is an instance of a dynamic class or not. Something like this:

1
2
3
4
5
6
7
8
9
10
11
12
import flash.utils.describeType;
 
var obj:Object = new Object();
obj.param1 = "param1";
obj.param2 = 23.3;
obj.param3 = 29;
obj.param4 = false;
 
for (var i:* in obj) trace(i+" :: "+obj[i]);
trace("---------");
var description:XML = describeType(obj);
trace(description);

Displays

param1 :: param1
param2 :: 23.3
param3 :: 29
param4 :: false
---------
<type name="Object" isDynamic="true" isFinal="false" isStatic="false">
  <method name="hasOwnProperty" declaredBy="Object" returnType="Boolean" uri="http://adobe.com/AS3/2006/builtin">
    <parameter index="1" type="*" optional="true"/>
  </method>
  <method name="isPrototypeOf" declaredBy="Object" returnType="Boolean" uri="http://adobe.com/AS3/2006/builtin">
    <parameter index="1" type="*" optional="true"/>
  </method>
  <method name="propertyIsEnumerable" declaredBy="Object" returnType="Boolean" uri="http://adobe.com/AS3/2006/builtin">
    <parameter index="1" type="*" optional="true"/>
  </method>
</type>

If you want to list the properties and methods separately, using the describeType() function, here’s how to do it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import flash.utils.describeType;
import flash.media.Camera;
 
var obj:Camera = new Camera();
var description:XML = describeType(obj);
 
trace("Properties:\n------------------");
for each (var a:XML in description.accessor) trace(a.@name+" : "+a.@type);
 
trace("\n\nMethods:\n------------------");
for each (var m:XML in description.method) {
	trace(m.@name+" : "+m.@returnType);
	if (m.parameter != undefined) {
		trace("     arguments");
		for each (var p:XML in m.parameter) trace("               - "+p.@type);
	}
}

Displays

Properties:
------------------
motionTimeout : int
activityLevel : Number
loopback : Boolean
fps : Number
height : int
width : int
motionLevel : int
bandwidth : int
muted : Boolean
name : String
index : int
keyFrameInterval : int
currentFPS : Number
quality : int
 
 
Methods:
------------------
setKeyFrameInterval : void
     arguments
               - int
setLoopback : void
     arguments
               - Boolean
setQuality : void
     arguments
               - int
               - int
setCursor : void
     arguments
               - Boolean
setMotionLevel : void
     arguments
               - int
               - int
setMode : void
     arguments
               - int
               - int
               - Number
               - Boolean
hasEventListener : Boolean
     arguments
               - String
dispatchEvent : Boolean
     arguments
               - flash.events::Event
removeEventListener : void
     arguments
               - String
               - Function
               - Boolean
willTrigger : Boolean
     arguments
               - String
addEventListener : void
     arguments
               - String
               - Function
               - Boolean
               - int
               - Boolean
toString : String

Please note that the function will not return any static properties the object might have. If you want to get the list of static properties too, you need to provide the class name as argument of the function and not an instance of the class:

1
2
3
4
import flash.utils.describeType;
 
var description:XML = describeType(Event);
trace(description);

Displays

<type name="flash.events::Event" base="Class" isDynamic="true" isFinal="true" isStatic="true">
  <extendsClass type="Class"/>
  <extendsClass type="Object"/>
  <constant name="COMPLETE" type="String"/>
  <constant name="FULLSCREEN" type="String"/>
  <constant name="UNLOAD" type="String"/>
  <constant name="CONNECT" type="String"/>
  <constant name="CLOSE" type="String"/>
  <constant name="SCROLL" type="String"/>
  <constant name="DEACTIVATE" type="String"/>
  <constant name="ENTER_FRAME" type="String"/>
  <constant name="ID3" type="String"/>
  <constant name="SELECT" type="String"/>
  <constant name="SOUND_COMPLETE" type="String"/>
  <constant name="TAB_CHILDREN_CHANGE" type="String"/>
  <constant name="INIT" type="String"/>
  <constant name="TAB_ENABLED_CHANGE" type="String"/>
  <constant name="MOUSE_LEAVE" type="String"/>
  <constant name="ADDED_TO_STAGE" type="String"/>
  <constant name="OPEN" type="String"/>
  <constant name="CANCEL" type="String"/>
  <constant name="REMOVED" type="String"/>
  <constant name="REMOVED_FROM_STAGE" type="String"/>
  <constant name="ADDED" type="String"/>
  <constant name="RENDER" type="String"/>
  <constant name="TAB_INDEX_CHANGE" type="String"/>
  <constant name="CHANGE" type="String"/>
  <constant name="RESIZE" type="String"/>
  <constant name="ACTIVATE" type="String"/>
  <accessor name="prototype" access="readonly" type="*" declaredBy="Class"/>
  <factory type="flash.events::Event">
    <extendsClass type="Object"/>
    <constructor>
      <parameter index="1" type="*" optional="false"/>
      <parameter index="2" type="*" optional="true"/>
      <parameter index="3" type="*" optional="true"/>
    </constructor>
    <method name="stopImmediatePropagation" declaredBy="flash.events::Event" returnType="void"/>
    <accessor name="type" access="readonly" type="String" declaredBy="flash.events::Event"/>
    <method name="preventDefault" declaredBy="flash.events::Event" returnType="void"/>
    <accessor name="currentTarget" access="readonly" type="Object" declaredBy="flash.events::Event"/>
    <method name="toString" declaredBy="flash.events::Event" returnType="String"/>
    <accessor name="target" access="readonly" type="Object" declaredBy="flash.events::Event"/>
    <accessor name="bubbles" access="readonly" type="Boolean" declaredBy="flash.events::Event"/>
    <accessor name="cancelable" access="readonly" type="Boolean" declaredBy="flash.events::Event"/>
    <method name="clone" declaredBy="flash.events::Event" returnType="flash.events::Event"/>
    <method name="formatToString" declaredBy="flash.events::Event" returnType="String">
      <parameter index="1" type="String" optional="false"/>
    </method>
    <accessor name="eventPhase" access="readonly" type="uint" declaredBy="flash.events::Event"/>
    <method name="stopPropagation" declaredBy="flash.events::Event" returnType="void"/>
    <method name="isDefaultPrevented" declaredBy="flash.events::Event" returnType="Boolean"/>
  </factory>
</type>

In this case the constants are all listed as sub-nodes of the main node and the properties and events are actually found in a sub-node called <factory> so the way to get the list of properties and methods will be relative to the <type><factory> node. Also, the isStatic attribute of the base <type> node will tell you that the target object is static or not.

November-28-08

How to preload AS3 clips

posted by admin

There are a lot of cases when your Flash animation is quite large in terms of file size. It contains images, perhaps some smaller .flv movies or a few “heavy” components.

In this case, if you publish your project somewhere on the web, you might have to wait a little, some times a little more, until the clip loads and starts playing. In this case it is very common (and quite frankly, necessary) to display something while your clip loads so the viewer knows there’s something going to happen and wait until your clip is completely loaded. In AS2 this wasn’t so hard. All you had to do was to move your animation to start from the third frame (but not necessarily), deactivate the “Export on first frame” setting from your symbols and components in the Library, place them on the second frame of your movie so they would load their assets (not necessary for all of them) by the time they would be instantiated, change the frame onto which classes were loaded from frame 1 to frame 2 and finally write some code on the first frame that would set an onEnterFrame event handler to display a preloader clip according to the size of your clip loaded so far. Lee Brimelow has made a nice video tutorial on how to preload flash clips, posted here: http://www.gotoandlearn.com/play?id=18. Again, this part isn’t necessary if you don’t want to display the amount of downloaded data and you only have a nice animation instead.

For ActionScript 3.0, the same thing is possible, only with the code changed to the AS3 syntax. You can download the example file from the link at the end of the post. However, this not always works. I’ve tried this with several components and looks like the method described earlier does not fully work. This is the case when using JumpeyeComponents’ TxEff or FlashEff. Even if you un-check the “Export in first frame” option from the Linkage Properties dialog box, there still is a considerable amount of data loading on the first frame. Don’t know why, yet… probably it has to do something with the embedded text (remember that TxEff and FlashEff need embedded characters for text effects). If this is the case, then you’ll probably have to wait a while until even your preloader shows up.

A workaround I’ve been using for this problem is to create the animation clip normally, without considering any preloading and then create a second clip I would use to load the first clip. This second loader clip would have all the preloading capabilities implemented into it. So, now I’m preloading an external .swf file. There’s also an item in JumpeyeComponent’s Knowledge base that addresses this issue: http://www.jumpeyecomponents.com/knowledgebase/TxEff-AS3.0/Preload-TxEff-animations~439/.

However, this arises another problem: in case of timeline animations, if that animation is in the external .swf file that you’re preloading, it so happens that the animation would start before the preloader is gone (while the preloading action is still going on). In this case, there’s a simple solution: move the entire timeline animation so it starts on the second frame and on the first frame place a stop() function. This way, your swf will not start the animation. Finally, after all the external .swf is loaded, just access the content in your loader object and instruct it to start playing from the second frame by using a gotoAndPlay(2) or gotoAndStop(2), if that’s the case.

You can check out these examples I’ve made.

July-24-08

How to install Flash components

posted by admin

During my days of customer support I’ve come across clients who asked for directions on installing the Flash components made by JumpeyeComponents. There are people who are just starting to work with Flash and are having trouble understanding key concepts or simply don’t know how some operations are made. This is why I thought it would be good to have detailed instructions on how to install .mxp files (Flash components setup files).

For starters, you need to have the installation file of the component, which comes in the form of a .mxp file. If you purchase a package of some sort, first you need to open that archive and retrieve the .mxp file(s). All Flash components are installed by a separate application called the Extension Manager. Usually, this application is installed together with other Adobe products (like Adobe Flash) but that is not necessary. So if you do not have the Extension Manager, you can download it from Adobe’s site: http://www.adobe.com/exchange/em_download/. If you are still using Macromedia Flash 8, you can use Macromedia Extension Manager 1.7 and you can download it from the same location. Please note that if you want to install Flash CS3 and ActionScript 3.0 components, you can only use Adobe Extension Manager 1.8 and Adobe Flash CS3. The previous version of Extension Manager will not be able to install components for Flash CS3.

Adobe Extension Manager

Before installing a component, it is recommended to close Flash CS3. Once you make sure that you have all the necessary applications installed and you have the component’s setup (.mxp) file, you can open that file simply by double clicking on it.

mxp file

Once the Extension Manager opens it will ask you if you really want to install the component. The window will display the manufacturer’s disclaimer or license agreement. If you agree to it, the installation process will go on, but if you decline the agreement, the component will not get installed.

Disclaimer and license agreement

Once the component is fully installed, a message will let you know about it.

Installation complete

Just press Ok and the newly installed component will appear in the components list.

Installed component

Now, you can open Flash CS3 and select Create new Flash File (ActionScript 3.0) from the welcome screen or selec File -> New from the menu (Ctrl+N on Windows or Command+N on Mac OS) and select Flash File (ActionScript 3.0) from the New Document window. You need to create a new ActionScript 3.0 file because FlashEff is a ActionScript 3.0 component and will not work in a ActionScript 2.0 project. Finally, if you open the Components panel (Ctrl+F7 on Windows and Command+F7 on Mac) you will see that the FlashEff component was installed, together with the patterns it has.

Flash CS3 Components panel

Also, in the case of the FlashEff component, there was a new Flash panel installed: the FlashEff panel. You can access it from the Window menu -> Other panels -> FlashEff Panel.

In ActionScript 3.0, the preferred way to execute actions at specific time intervals is the use of the new Timer class. In ActionScript 2.0, we had the setInterval() function and this was the way to use it:
- write a function that would be called every time the time interval passed the limit
- call the setInterval() function that would receive as parameters the object that has the target function defined (not always necessary), the name of the function (or a reference to it), the time interval at which to call the target function and the list of parameters for the target function (also not necessary)
- to stop the time interval there should have also been a variable defined to hold the interval id and then call clearInterval() with the interval’s id as parameter.

AS2 example – call a function 10 times

For example, the next piece of code will call timeHandler 10 times and then interrupt the repeated calls of the function:

var counter:Number = 0;
var intervalID:Number;

function timerHandler(param:String):Void {
counter++;
trace(“This function has been called “+counter+” times with the \”"+param+”\” parameter”);
if (counter == 10) clearInterval(intervalID);
}

intervalID = setInterval(timerHandler, 1000, “test”);

AS3 example

For AS3, the steps are similar but setInterval() was replaced by the Timer class. Here is the above code translated into AS3:

import flash.utils.Timer;
import flash.events.TimerEvent;

var counter:int = 0;
var timerObject:Timer = new Timer(1000, 10);
timerObject.addEventListener(TimerEvent.TIMER, timerHandler);
timerObject.start();

function timerHandler(eventObject:TimerEvent):void {
counter++;
trace(“This function has been called “+counter+” times”);
}

AS3 code explained

You can see that when creating a new instance of the Timer class, the constructor has two parameters passed to it: the first is the time interval (in milliseconds) and the second is the number of repetitions, that is the number of times to call the handler function. If the second parameter is not given or it’s 0, then the timer repeats infinitely. Next, you need to define the handler function for the TimerEvent.TIMER event, which gets dispatched every time the time interval is passed. The Timer class also dispatches another event, TimerEvent.TIMER_COMPLETE. This event is dispatched only when the timer object has finished the number of repetitions. If the repeatCount, the second parameter of the Timer constructor is not defined or it’s 0, then the TIMER_COMPLETE event will never get called. Once you create the Timer instance, you need to start it (timerObject.start()) otherwise it won’t have any effect.

As you can see, for the AS3 version, you cannot pass any parameters directly to the timer event handler functions. If you want to get the same result as the AS2 example, then you need to create another function that would be called by the timer event handler and get the parameter passed to this second function:

function timerHandler(eventObject:TimerEvent):void {
callback(“test”);
}

function callback(param:String):void {
counter++;
trace(“This function has been called “+counter+” times with the \”"+param+”\” parameter”);
}

The Timer class

The Timer object is more complex and offers us more information on the current interval calls. We can have access to the number of repetitions the Timer object has reached (timerObject.currentCount), the total number of repetitions (timerObject.repeatCount), the time interval (timerObject.delay) and we can even find out if the Timer object is running or not (timerObject.running).

By using the Timer class, you also have the ability to stop the repetitions (timerObject.stop()) and then resume it, if you call the start() method again. It even has the possibility to reset the counter (timerOject.reset()) and the Timer object will start the repetitions all over again.

Get the number of repetitions from the Timer object

As mentioned previously, you can access different parameters of the Timer object and you can do it even in the timer event handler function. The next example displays the number of times the function has been called, without having to define an extra variable for that:

import flash.utils.Timer;
import flash.events.TimerEvent;

var timerObject:Timer = new Timer(1000, 10);
timerObject.addEventListener(TimerEvent.TIMER, timerHandler);
timerObject.start();

function timerHandler(eventObject:TimerEvent):void {
trace(eventObject.target.currentCount+” repetitions out of “+eventObject.target.repeatCount);
}

As you can see, the Timer class is a welcome addition to the ActionScript 3 framework. Enjoy it.