Categories Displayed in Flash

Archive for the 'as3' Category

Fix for Error #1063: Argument count mismatch on BitmapData Expected 2, got 0.

Normally creating blank BitmapData requires you pass in an the width and height in pixels.  But what about when you embed an image with a linkageid?  You'll get the above error trying to create a new myEmbeddedImage(); unless you pass it with two numbers, even if they don't mean anything e.g.

var bdata:BitmapData = new imageInLibraryLinkageID(0,0);

I would have thought that these would be optional for embedded assets.  Fix originally discovered here.

Flash: Beware the Garbage Collector

Of all the major changes in AS3, this has been the most problematic....things hanging out off the display list, unreachable. I discovered a new way to get these "voices from the grave" to happen this eve.

We are instantiating new MovieClip classes for the stage via

  1.  
  2.      MovieClipClassReference = getDefinitionByName(styleMC) as Class;
  3.      try{
  4.            curPageClip = new MovieClipClassReference (curPageText);
  5.          }catch (e:Error){
  6.           curPageClip = new MovieClipClassReference ();
  7.       }

The idea being sometimes they accept an argument, in other times they don't. If it doesn't work the first time, then we try the second. Unfortunately this means that there are now 2 MovieClips, with all their assets hanging out in memory, but lacking the brains/script because the constructor errored out! In our case the error was 'voices from beyond' as the sounds embedded on the timeline were playing in the background even though there only appeared to be one instance on the stage stopped at the beginning.

The short solution for us was to have all classes accept a constructor, even if they don't do anything with it. A cleaner approach is to introspect the class looking for the amount of arguments in the constructor...

  1.  
  2.        var desc:XML = describeType(MovieClipClassReference );
  3.         var xmlL : XMLList = desc..constructor.parameter;
  4.         trace("Constructor Parameters " + xmlL.length());
  5.         if( xmlL.length() == 1) {
  6.                 curPageClip = new MovieClipClassReference (curPageText);
  7.         }else if( xmlL.length() == 0) {
  8.                 curPageClip = new MovieClipClassReference ();
  9.         }

Flash: Actionscript 3.0 ReferenceError: Error #1056 Cannot create property

Also discovered here Quote:

In Flash CS3, when you have instances (Movieclips) on the main timeline (Stage) with instance name on them and “Automatically declare stage instances” is off (File->Publish Setting->Flash->Actionscript 3.0 setting), You will need to declare properties for the document class with the same instance names or else you will get the error messages…

Like:


Cannot create property ANamedClipOnTheTimeline_mc on com.yoursite.DocumentLevelClass


at flash.display::Sprite/constructChildren()
at flash.display::Sprite()
at flash.display::MovieClip()
at com.yoursite.DocumentLevelClass()

In my case this was due to copying a button that didn't belong, hidden behind another clip.  To Find it I selected all, Right Clicked, selected distributed to layers, and then deleted the offending layer named that of the clip named in the error.

Flash: Detecting the end of an animation

Say you have an animated character in a game, that others need to know when they are through playing their animation. Here are a few approaches:

Let's first assume we have a generic object named 'player_mc' that is our animation. We also have a centralized controller script closer to the root, that has a function like:

  1. function onAnimationComplete(evt:Event = null):void{
  2. //do something
  3.  currentPlayer = evt.target as MovieClip;
  4.  currentPlayer.gotoAndStop("still");
  5. }

Note that we use evt = null just in case we want to use call the function without passing it an event.

1) Using addFrameScript

  1. var init:Boolean;
  2. if(!init){
  3.        /// !init check, this block is only needed when pasting on timeline
  4.       // to keep it from activating more than once when the movieClip recycles
  5.         addFrameScript(totalFrames -1, onAnimationComplete);
  6.         init = true;
  7. }
  8.  
  9.  

Just remember if doing that approach, addFrameScript uses a frame number one less that what you see in Flash.

This approach is safer when indexing frame labels prior (e.g. with UIUtil) to map say a frame label of "AnimationFinishedFrame" to the frame number for addFrameScript to use.

  1. addFrameScript(com.troyworks.ui.UIUtil.getNumberOfFrameLabel("AnimationFinishedFrame", onAnimationComplete);
  2.  

2) Using Event Bubbling

Just communicate up the display list.

  1. player.addEventListener("ANIMATION_COMPLETE", onAnimationComplete);

Then

  1. //inside the player on last frame of the player animation
  2.  
  3. stop();
  4. dispatchEvent(new Event("ANIMATION_COMPLETE", true, true));

For more info see here.

3) Use Singleton/Static or Stage as a message bus.

like 2 but using the stage or some other easy to access to communicate without bubbling.

4) Poll for Progress

This is a bit more work, but get's you the ability to find out more about the progress, eg. showing a progress bar for percentage played.

  1. player.addEventListener(Event.ENTER_FRAME, onENTER_FRAME
  2.  
  3. function onENTER_FRAME(evt:Event):void{
  4.   var playermc:MovieClip = evt.target as MovieClip;
  5.  
  6.    if(playermc.currentFrame == playermc.totalFrames){
  7.        onAnimationComplete();
  8.    }
  9. }

Hope that helps.

Flash: Fast Prototyping and Sketching UI with FlowControl

While I enjoy the new power of Flash9/AS3.0, one of the things I really dislike about the AS3, is how much extra work to do basic things like setup buttons to do simple timeline control, this is especially hard on designers and animators who don't code. I agree with 5etdemi post 4 years ago, the basics have ironically gotten harder to do.

What wrong with ECMAScript/Actionscript? Well, it is not especially well suited for certain tasks, the worst of which is time-based/timeline-oriented animation and declarative drawing. I mean, it seems pretty ironic that ActionScript is derived from ECMAScript which was primarily oriented at scripting in a text-based environment, HTML and the DOM. Simply put, ActionScript has leaned more and more towards heavy lifting text operations (like RegEx and the new XML implementation) and less towards building programmatically what Flash was originally meant for, animation.

While there are useful utilities like Lee Brimelow's nice event generator utility, I wanted less, as even if being good with actionscript, when you have a few minutes to put together something for (or during!) a client/skype meeting, scripting isn't really an option. Thankfully AS3 has some tricks to help!

(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.) ( press RIGHT arrow key to advance)

One tennant of Sketch is using the type and instance names to do most the event binding work, largely this is to allow Designers to stay on the timeline, but the same could apply to objects created in actionscript as well. So in the above example there are 2 scenes, and a bunch of empty frames, and a nav control. What's special is the buttons you see are actually just semi-transparent buttons (I call InvisiButtons) that have instance names like 'next', 'prev', (shown in the button names) there is no other script on the timeline for them. That via the FlowControl listening to ADDED event are autowired up to call 'nextFrame()' , 'prevFrame()' etc. These InvisiButtonscould be used as a hotspot over a comped image or basic text and wireframe graphics, allowing low to high fidelity comps to be created.

In this example a ENTER_FRAME event updates the TextField off to the right to show the current scene, frame et, to show where you are.
FlowControl has some other nifty features.

  • optional features is the fadein, fadeout effect, with configureable color, so while there is a normal timeline, the fade effect is free and ads a bit of polish IMHO.
  • tooltips telling you where the buttons go/do.
  • keypress for left/right arrow to go to the next previous frame, escape to goto first frame-useful for slide shows
  • XXX_autoBtn. If it sees this pattern that button will generate an XXX event (e.g. sayHi_autoBtn generates a new Event("sayHi"), which anybody is free to listen to.

All these are in the example (as well as all the code for FlowControl) on code.google.
Flow Control can be used 'embedded' as the document level class (or extending from it) or loaded as an external swf, and I'll be demoing that in the future. That latter feature is more targetted to creating highly skinnable games which I'll be covering in future blog posts.

Flash: TextField actionscript hyperlink in AS3.0

In this article we cover how to get flash.text.TextFields HTML anchors/hyperlinks, to call actionscript functions, how to use CSS to style the up, over/hover and down/active and [UPDATE] visited states similar to hyperlinks in normal html.

The applications of this are numerous. Perhaps clicking a hyperlink will deeplink into your Flash application without navigating away, or perhaps it would open up a dictionary definition on the term.

(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)

Here's the FLA

In this example clicking on the 3 links will show in the bottom text box where the link was meant to go.  This is based on the event handler receiving a flash.events.TextEvent.LINK event, as dispatched by formatting the '<a href=..' to dispatch the link event instead of the default navigateToURL.

The 'blog1' and 'blog2' links both go to the same URL, when either are clicked on both will change to the visited style.   This change color requires a hack, as the 'a:visited' isn't one of the CSS tags supported by Flash.   However we CAN overwrite the CSS style to display a different style, on the click.   This is more complex as we have to figure out, a) are we interested in changing all links that point to that location? or b) just the one that was clicked on?.   Keep in mind that this is a hack, and differs from the way browsers behave in that the links won't persist past that flash session, or across different TextFields unless you code it that way.

You can detect mouseRollOvers using the TextField.getCharIndexAtPoint(x:Number, y:Number) This will return the current character the mouse is over. From there you walk forward and backwards to the end of the word (looking for whitespace), and then presumably do something useful. At kidthing on much of the site we used this (minus rollovers) for adding graphic end signs which I cover here.

An example with with code of this is at gamelan's site. Source for a simpler example that highlights text is presented here. What he does in that is search through the body text for the desired word, draw a rectangle to match that words boundaries, place it over the TextField and adjust it's blend properties so that it appears highlighted, that shape could easily have button like properties. Another fun example is his inspiring labs.

In a future article I'll discuss how to clean and process HTML, and replace the links with internal flash link's if you are using CMS'd, progressive enhancement websites, with Flash as the RIA style/presentation layer.  So the same HTML will work as expected when in HTML only site (e.g. for search bots) or in the Flash only.

  1.  
  2.  
  3. import flash.text.StyleSheet;
  4. import flash.events.TextEvent;
  5.  
  6. var style:StyleSheet = new StyleSheet();
  7.  
  8. var hover:Object = new Object();
  9. hover.fontWeight = "bold";
  10. hover.color = "#00FF00";
  11. var link:Object = new Object();
  12. link.fontWeight = "bold";
  13. link.textDecoration= "underline";
  14. link.color = "#555555";
  15. var active:Object = new Object();
  16. active.fontWeight = "bold";
  17. active.color = "#FF0000";
  18.  
  19. var visited:Object = new Object();
  20. visited.fontWeight = "bold";
  21. visited.color = "#cc0099";
  22. visited.textDecoration= "underline";
  23.  
  24. style.setStyle("a:link", link);
  25. style.setStyle("a:hover", hover);
  26. style.setStyle("a:active", active);
  27. style.setStyle(".visited", visited);
  28.  
  29. html_txt.styleSheet = style;
  30. var htm:Array = new Array();
  31. htm.push("<br><p align='center'>Example of HTML hyperlinks calling actionscript in AS3.0</p>");
  32. htm.push("<p> Click to visit <a href='event:http://www.TroyWorks.com'>home</a> ");
  33. htm.push("<a href='event:http://www.TroyWorks.com/blog/'>blog1</a> ");
  34. htm.push("<a href='event:http://www.TroyWorks.com/blog/'>blog2</a>");
  35. html_txt.htmlText= htm.join("");
  36.  
  37. function onHyperLinkEvent(evt:TextEvent):void {
  38.         trace("**click**"+ evt.text);
  39.         define_txt.text = ( "Clicked on " + evt.text);
  40.         var str:String = html_txt.htmlText;
  41.         str = str.split("'event:"+evt.text+"'").join("'event:"+evt.text+"' class='visited' ");
  42.         html_txt.htmlText = str;
  43. }
  44.  
  45. html_txt.addEventListener(TextEvent.LINK, onHyperLinkEvent);

Flash: 4 Tricks for using MovieClips as Buttons

So here are 4 tricks I've found useful:

  1. Use actionscript to create the Button behavior (enlarging etc), centralizing it in one place.
  2. Use clips styled in the IDE, and copy their style/filters for mouse over, down, disabled state.
  3. Use mouseEnabled (and alpha/brightness) to temporarily disable a button
  4. Use the instance name as the label, and in the event parsing.

(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)

Styling MOUSE_OVER, MOUSE_DOWN States

Similar to CSS centralizing style, centralizing behavioral style offers the same maintenance advantages.   Using clips on the stage for style allows the designer to visually see what's desired, rather than spending countless iterations tweaking actionscript to get it right, it's a good handoff in team based approach.   I also sometimes use describeType 'autowire' any buttons of particular classes.   For the disabled state I stacked two brightness filters ontop of each other.

Styling it to send all the events to a central controller (MVC UCM style), allows things to be debugged far easier than when events are going everywhere, and the controller has internal state, respond appropriately, say ignoring all clicks during loading, without having to rewire all the various components.

For 1 and 2 here's the underlying code. Notice I use mouseChildren = false to keep the label textfield from generating events.

  1.  
  2. function configureMC_Button(ary:Array, addL:Boolean = true):void {var a:MovieClip;
  3.  
  4. var i:int = 0;
  5.  
  6. var n:int =ary.length;
  7.  
  8. for (true; i < n; ++i) {
  9.  
  10. a = ary[i];
  11.  
  12. if (addL) {
  13.  
  14. a.addEventListener(MouseEvent.MOUSE_OVER, onMouseOverHandler);
  15.  
  16. a.addEventListener(MouseEvent.MOUSE_OUT, onMouseOutHandler);
  17.  
  18. a.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDownHandler);
  19.  
  20. a.addEventListener(MouseEvent.MOUSE_UP, onMouseOverHandler);a.addEventListener(MouseEvent.CLICK, onMouseClickHandler);
  21.  
  22. a.mouseChildren =false;
  23.  
  24. } else {
  25.  
  26. a.removeEventListener(MouseEvent.MOUSE_OVER, onMouseOverHandler);
  27.  
  28. a.removeEventListener(MouseEvent.MOUSE_OUT, onMouseOutHandler);
  29.  
  30. a.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDownHandler);
  31.  
  32. a.removeEventListener(MouseEvent.MOUSE_UP, onMouseOverHandler);
  33.  
  34. a.removeEventListener(MouseEvent.CLICK, onMouseClickHandler);
  35.  
  36. }
  37.  
  38. }
  39.  
  40. }
  41.  
  42. function onMouseClickHandler(evt:Event):void {
  43.  
  44. var mc:MovieClip = MovieClip(evt.target);
  45.  
  46. output_txt.text =(" \r"+ mc.label_txt.text + "**Clicked **");
  47.  
  48. }
  49.  
  50. function onMouseDownHandler(evt:Event):void {
  51.  
  52. var mc:MovieClip = MovieClip(evt.target);
  53.  
  54. mc.filters = downTreatment.filters;
  55.  
  56. }
  57.  
  58. function onMouseOverHandler(evt:Event):void {
  59.  
  60. var mc:MovieClip = MovieClip(evt.target);
  61.  
  62. mc.scaleX = mc.scaleY = 1.2;
  63.  
  64. mc.filters = overTreatment.filters;
  65.  
  66. }
  67.  
  68. function onMouseOutHandler(evt:Event):void {
  69.  
  70. var mc:MovieClip = MovieClip(evt.target);
  71.  
  72. mc.scaleX = mc.scaleY = 1;
  73.  
  74. mc.filters = [];
  75.  
  76. }
  77.  
  78. overTreatment.visible = downTreatment.visible = disabledTreatment.visible = false;
  79.  
  80. configureMC_Button([a_btn, b_btn, c_btn, d_btn, e_btn, f_btn, g_btn]);

Enabling and Disabling via ActionScript

You can disable/enable a clip simply by using the mouseEnabled field which will turn on or off mouse events.   Contrast this with the approach of adding/removing listeners to enable or disable a button, which may have multiple listeners for different classes, you can't see, so you never know if you got them all.

  1.  
  2. function setEnabled(  ary:Array, enable:Boolean = true):void {var a:MovieClip;
  3.  
  4. var i:int = 0;
  5.  
  6. var n:int =ary.length;
  7.  
  8. for (true; i < n; ++i) {
  9.  
  10. a = ary[i];
  11.  
  12. if (enable) {
  13.  
  14. a.mouseEnabled = false;
  15.  
  16. a.filters =[];
  17.  
  18. } else {
  19.  
  20. a.mouseEnabled = false;
  21.  
  22. a.filters = disabledTreatment.filters;
  23.  
  24. }
  25.  
  26. }
  27.  
  28. }
  29.  
  30. setEnabled([d_btn, e_btn], false);

Using the instance name as id.

Using the instance as the basis for identification, saying parsing it for use the label, and in the event, can make things more uniform than having buttons dispatching events,.   In internationalized apps where the label changes based on whatever language is present, the instance name can serve as a key to finding the appropriate text in some multilanguage dictionary, or even show when a label is missing.

In Closing
Using a single movieClip has many advantages,  only one skin has to be created instead of 4-5 for a SimpleButton.   When handled in the way outlined above it has many of the advantages of being a component, without the work of being a full blown one.   It minimizes the number of classes/library items when each button is created with a unique label hard coded into it.

In conjunction with a tweening engine, it allows for what I call momentum styled buttons.   Buttons that don't have crisp state changes like SimpleButton attempts on the mouse up/over/down. Things that fade up, and down, like real world lightbulbs, cars.   When used with ColorTransform this can allow for adaptively styled UI, like that of CSS.

There are also safety benefits. In AS3.0 the timeline is purely script driven, there are still bugs when using multiple frames to manage state on particular versions of the flash player.   I've had odd issues with sound not firing or not stopping firing, components blowing up when in tweens or in timelines.

Using fl.controls.* with FDT (and Flash CS3)

I Recently upgraded to FDT 3.0 Professional...I highly recommend if you're doing heavy actionscript projects. It's pricey, but will pay for itself quickly.

Using fl.controls with the syntax checking took a bit of research. Turns out you have to follow the steps as

  • Create a new FLA, name it CS3Controls
  • drag all the components you need into the Library
  • In File> Publish Settings > Flash > checkmark "Export SWC"
  • publish it
  • copy the CS3Controls.swc to someplace you'll remember (e.g. a common classpath or whatever app that uses them's lib folder)
  • - Now in FDT, add your SWC to your project, and in the Flash Explorer panel, right-click and add that SWC file to your classpath
  • once that swc is visible in the FDT Flash Explorer, right click over it. "Source Folder">"Add to Classpath"
  • after a moment you will see it above the packages, if successful, clicking the plus will show you all the classes inside it...very cool FDT team!
  • in your AS class just proceed as normal eg.: <code> import fl.controls.*</code>

Found this post

AS3: Function.apply

When using method closures, it sometimes it helps to have some default arguments, and later some optional arguments to pass. This example will look at passing additional params when using Elastic tweens.

Using Function.apply it's pretty easy to concat the arguments into one argument list. Though it should be noted that it's significantly slower than just passing them, which is appropriate if the number of arguments is of a known quantity.

  1.  
  2. ////// parameters for our tween, some of these will change over time //////
  3. var t:String = 0; //current time
  4. var b:String = 0; //begin val
  5. var c:String = 1; //change val
  6. var d:String = 1; //duration
  7.  
  8. var _fA:Array = [1, 2]; //parameters for elastic tweening
  9.  
  10. function _f(a:Object, b:Object, c:Object, d:Object, e:Object = null, f:Object = null, g:Object  = null ):Object {
  11. trace("a:" + a + " b:" + b + " c:" + c + " d:" + d + " e:" + e + " f:" + f + " g:" + g);
  12. return a + b + c;
  13. }
  14.  
  15. //note that the first value is null, as when using a method closure,
  16. //the scope the function is being evaluated in is fixed to that of the class.
  17.  
  18. var calc = _f.apply(null,[t,b,c,d].concat(_fA));
  19.  
  20. trace("result " + calc);

A faster way is to avoid array manipulations, and just route based on the number of arguments. e.g. arg1, arg2 are

  1.  
  2. var calc
  3.  if(numOfArgs==4){
  4.        calc = _f.apply(null,[t,b,c,d]);
  5.   } else if (numOfArgs == 6){
  6.       calc = _f.apply(null,[t,b,c,d,arg1,arg2]) ;
  7.   } else if (numOfArgs == 8){
  8.       calc = _f.apply(null,[t,b,c,d,arg1,arg2,arg3,arg4]) ;
  9.   }

//a:t b:b c:c d:d e:1 f:2 g:null
//result tbc

AS3: Array.filter R0xr!

Array in AS3 has some nifty features that make managing and manipulating active data much easier. Thanks to Brandon Hall's nooks and crannies presentation at LA Flash for getting me to look. Here's an example of using Array.filter

Here's the minimum filter that doesn't do anything. I default the last parameters as often filters are useful outside of iterating over arrays, but the filter method nicely tells the filter where it is via the 'index' and a reference back to the Array.

  1.  
  2.         public class Filter {
  3.                 public function passesFilter(item:*,  index:int= 0, array:Array = null):Boolean{
  4.                         var passes:Boolean = true;
  5.                         return passes;
  6.                 }
  7.         }

Inside com.troyworks.data.filters. I've created a family of filters, in particular RangeFilter that allows inclusive and exclusive of a given range. Here's what a 3-8 filter looks like:


3-8 filter.. 0123456789012345678
* inclusive ---[PASS]----------
noninclusive ---]PASS[----------

The real power of filters is they can be stacked. Here's an example of using a color filter, that looks for color values in the midgray band, but adds an additional filter so that values to close to gray are thrown out.

  1.  
  2. //find values from 0x555555 to 0xBBBBBB non-inclusive on both sides
  3.         var midsFilter:ColorStatisticFilter = new ColorStatisticFilter( ColorUtil.GRAY5, ColorUtil.GRAYB, false, false);
  4.         midsFilter.distanceFromShadeFilter = new NumberRangeBooleanFilter(36, 255);
  5.      // second param needs to be null as this filter is a function closure instead of an anonymous function.
  6.       var midColors:Array = indexedColors.filter(midsFilter.passesFilter,null);
« Previous Entries Next Entries »