Custom component for distribution – live preview detection

It’s been a while since I worked on a custom component for distribution, to auto-install in the Adobe Extension Manager.

Many online tuts and official documentation assume that you want to extend the standard Flash UI Component framework. Building components without using this framework is a bit of a black art. Kudos to David Barlia’s blog post at Studio Barliesque for answering a lot of my questions regarding this approach.

When you set up a custom component and drag it to the stage from the library, it is still just a static symbol. However a component that comes from the ‘Components Panel’, (i.e. you’ve moved the FLA or SWC to the folder  Adobe Flash CS6/Common/Configuration/Components ) actually runs the component when you drag it to the stage. It’s great that you can see something happen on the stage, but sometimes you don’t want it to do the same thing in authoring or compiled modes.

The common solution to handle this is to set up a separate movie which will display when you drag on the component, called the live preview. (for example this is described in this page in tutsplus)

However I was interested in the component detecting whether it was being displayed in authoring mode or compiled. Unfortunately it’s not as easy as you’d think. Capabilities.playerType thinks its running ‘External’ either way. So, I was at a road block until a few years ago David Barlia at Studio Barliesque managed to find the answer for me.

The following method can detect whether the component is running as a live preview in authoring mode, or in a compiled SWF.

protected function isLivePreview():Boolean {
return (parent != null && getQualifiedClassName(parent) == "fl.livepreview::LivePreviewParent");
}

With this method you can use the same class for the component and have it work differently depending on whether it is a live preview or not.

Tagged with: , ,
Posted in Flash

From audio streaming synching to timed MovieClips

I’ve been working recently on an iPad app with a lot of vector animation. Sometimes, due to transparency, effects, etc, playback of the animations were not quite up to the frame-rate we were hoping for and for our purposes the speed of the animation was more important than skipped frames. While we played around with removing elements to improve the animation speed, I played around with scripting solutions.

I noticed that when we played streaming audio that the frame rate bumped right back up to the right speed. Although the animation could skip the occasional frame, the speed was correct. Thinking about it, this is what’s to be expected as it wouldn’t be acceptable for the audio to stutter, so to ensure the audio was synched to the animation, it could be necessary for Flash to skip animation frames. But what was news to me, is that the streaming audio doesn’t need to be in the same movieclip as the animation! If for example, you have a looping movieclip with a short streaming audio clip(with sound volume adjusted to zero if you like), this forces ALL movieclips that play to place a higher priority on playing at the correct speed over skipping frames.

Interesting, but practically I don’t think it’s really a workable solution to be constantly streaming audio, I’m sure this would decrease performance. But it got me thinking about creating a custom MovieClip class that always maintains the correct frame rate using TweenLite. Gave it a go and it worked great! See below for the class.

NB: Considerations with this class:

  1.  it could skip a frame that contains scripting. (This wasn’t an issue here, but is an issue that could be addressed in a revision to the class)
  2. the class assumes a ‘stop’ in the final frame of the class. (Again this could be resolved with an added method for example, called ‘loop’
  3. if you manually call gotoAndStop on the clip, you also need to call stop (this is because ‘gotoAndStop’ was called by the Tween class responsible for keeping the movieClip playing, so if ‘gotoAndStop’ was called I couldn’t presume that the animation is over.
package com.craiggrummitt.display
{
import com.greensock.TweenLite;
import com.greensock.easing.Linear;
import com.greensock.plugins.FramePlugin;
import com.greensock.plugins.TweenPlugin;

import flash.display.MovieClip;

public class MovieClipTimeBase extends MovieClip
{
public function MovieClipTimeBase()
{
super();
TweenPlugin.activate([FramePlugin])
}
override public function gotoAndPlay(frame:Object, scene:String=null):void {
this.gotoAndStop(frame);
play();
}
override public function play():void {
TweenLite.killTweensOf(this,false,{frame:true});
var secs:Number=(this.totalFrames-this.currentFrame)/stage.frameRate
TweenLite.to(this,secs,{frame:totalFrames,ease:Linear.easeNone});
}
override public function stop():void {
TweenLite.killTweensOf(this,false,{frame:true});
super.stop();
}
}
}


Tagged with: , ,
Posted in Flash

Spanish Flash terms

When I began working in South America, I soon realized I needed to brush up on my Flash terms to be able to communicate… Here is a list of some.

Error – error (start with an easy one!)
Warning – advertencia
Layer – capo
Frame – cuadro
Library – biblioteca
MovieClip/Movie – pelicula
Properties – propiedades
Preferences – preferencias
Symbol – símbolo
Text field – campo de texto
Class – clase
Window – ventana
Height, width – altura, ancho
Source – fuente
Font – fuente         

I remember having at least one confusing source/font conversation!

No-one understood when I called myself a ‘desarrollador de Flash’ (Flash developer) either, ingeniero de sistemas(systems engineer) seems to be the term of choice.

Tagged with:
Posted in Flash

Strangeness in custom component parameters

I decided today to systematically analyse a problem that’s bothered me for several years: What determines whether a parameter setter for a custom component will be called?

Today I’ve finally worked it out, and discovered that my lack of clarity was justified…

So I have a simple custom component with one Number parameter:

package  {

     import flash.display.MovieClip;
     import flash.events.Event;

     public class CustomComponent extends MovieClip {

          private var _aNumber:int;
          [Inspectable (type="Number")]
          public function get aNumber():int {return _aNumber;}
          public function set aNumber(value:int):void {
               trace("set number "+value);
               _aNumber = value;
          }

          public function CustomComponent() {
               loaderInfo.addEventListener(Event.INIT, onInit);
          }
          private function onInit(event:Event):void {
               trace("aNumber="+aNumber);
          }
     }
}

This gives the parameter aNumber:

Now when this parameter is set to ‘1’, and we test the movie, we see the following trace:

set number 1
aNumber=1

When this parameter is set to ‘0’ we see the following:

aNumber=0

So the INIT event is still dispatched, but the parameter setter is NOT called! Why? My hypothesis is that it’s not called as it is the same as the default value for the parameter. To test this hypothesis, I change the default for the variable:

          [Inspectable (type="Number",defaultValue=100)]

Now, with the parameter set to ‘0’ the trace is:

set number 0
aNumber=0

So obviously the default does affect whether the setter is called. It appears as though:

  • if the defaultValue and the parameter values are the same, the parameter setter is not called.
  • if the defaultValue and the parameter values are different, the parameter setter is called.

BUT – so far we’ve only looked at ONE parameter, what if there are several? this is where the plot gets thicker!

I’ve added two additional parameters to my custom component, a String, and a Boolean:

package  {

     import flash.display.MovieClip;
     import flash.events.Event;

     public class CustomComponent extends MovieClip {

          private var _aBoolean:Boolean;
          [Inspectable (type="Boolean")]
          public function get aBoolean():Boolean {return _aBoolean;}
          public function set aBoolean(value:Boolean):void {
               trace("set boolean "+value);
               _aBoolean = value;
          }

          private var _aNumber:int;
          [Inspectable (type="Number")]
          public function get aNumber():int {return _aNumber;}
          public function set aNumber(value:int):void {
               trace("set number "+value);
               _aNumber = value;
          }

          private var _aString:String;
          [Inspectable (type="String")]
          public function get aString():String {return _aString;}
          public function set aString(value:String):void {
               trace("set string "+value);
               _aString = value;
          }

          public function CustomComponent() {
               loaderInfo.addEventListener(Event.INIT, onInit);
          }
          private function onInit(event:Event):void {
               trace("aNumber="+aNumber+", aString="+aString+", aBoolean="+aBoolean);
          }
     }
}

Now we have three parameters:


If we leave the three parameters with their defaults, we only see the trace from the constructor:

aNumber=0, aString=null, aBoolean=false

But if we change just one parameter, in addition to the constructor trace, we see the trace from all three parameter setters:

set boolean true
set number 0
set string
aNumber=0, aString=, aBoolean=true

So, long story short, the custom component rule of strangeness breaks down to the following:

  • If none of the parameters are different to their defaults, none of the parameter setters run.
  • If JUST ONE of the parameters is different to the default, ALL of the parameter setters run.

strrrange…

Tagged with: ,
Posted in Flash

Captivate error loop on unload

Obviously I’m working a bit with captivate files lately, my last three posts have been about the joys of using them.

My latest problem is that when I request a Loader object to unload a captivate generated swf, I immediately get a series of never-ending errors, that repeats the same thing:

TypeError: Error #1009: Cannot access a property or method of a null object reference.     
at captivate.veela_as3::rdSwfLoader/IsParentSlidelet()     
at captivate.veela_as3::rdItem/getParentCurrFrame()     
at captivate.veela_as3::rdSwfLoader/getParentCurrFrame()     
at captivate.veela_as3::rdSwfLoader/rdSwfLoaderEnterFrame()

If I was permitted to use FlashPlayer 10 in this project I would probably try unloadAndStop() or if that didn’t work, uncaughtErrorEvents, but unfortunately this project requires Flash player 9. Nothing worked in attempting to prevent this error.

In the end I just commented out the line:

loader.unload();

and instead just removeChild(loader) and set loader to null. For some reason the Captivate swf spits the dummy if it doesn’t have a parent.

What a baby.

Tagged with:
Posted in Flash

Solved! The mystery of the captivate ghosts…

I was finding that all of my swfs exported from Captivate, contained slight blurriness, and left stray artifacts and ghosting on transitions. Why oh why… It was only occurring on PCs and only when loaded into the main projector. And yet when I setup an alternative loader.fla the blur and artifacts were gone! There had to be a reason. After some time eliminating causes, I’ve found the cause, one line of code. Which to be honest I’m still not sure why it would be causing the problem, but it does:

stage.showDefaultContextMenu = false;

Fortunately it’s not such a big deal to remove this line, so. Problem solved. Wins most obscure bug solution of the year though.

Tagged with:
Posted in Flash

Captivate communicating with Flash

I think it’s a little strange that Captivate is owned by the same company as Flash and exports ‘swf’ format, yet there’s no option to simply dispatch a Flash event. Which makes communication between a Flash holder and the Captivate movie problematic.

There are a few solutions(i.e. hacks!) out there:

  1. Import a flash movie on the final frame of the movie, which contains the actionscript that we wanted to execute, perhaps by calling a function on the root…
  2. pipwerks blog had a very interesting lateral thinking solution: Captivate actually permits you to call a javascript function. Flash can be listening to this function with a callback.

I found both of these methods with their drawbacks in their own ways.

Solution 1 has potential scope issues, that the child Flash movie would have to know exactly the path to call the function, and could easily be problematic once we start incorporating preloaders.

Solution 2 (Captivate->HTML[Javascript]->Flash communication). Although a neat solution, I always try to avoid this sort of thing if possible just to avoid the possibility of browser / cross-platform issues, etc.

I was looking at other possibilities within Captivate and discovered that one Flash-esque thing that Captivate can do, is set a variable. I realized that quite a simple and neat solution was possible:

After loading the Captivate file, the parent Flash file can be constantly checking if the Captivate file has set the variable (on enter frame) and when it has, trigger an action.

This is easily accessed. I had a variable called ‘completed’, and I checked it via:

loader.content.completed

Tagged with:
Posted in Flash

My Review of Introducing Starling

Originally submitted at O’Reilly

Building GPU Accelerated Applications

Great intro to Starling, but not perfect

By craiggrummitt from Melbourne, Australia on 1/22/2012
4out of 5

Pros: Easy to understand, Helpful examples

Cons: Too many errors

Best Uses: Expert

Describe Yourself: Developer

A great introduction to Starling, well structured, well explained and contains comprehensive examples.

The only major drawback is there are obvious editorial issues in the text and bugs/errors in the code examples.

But – it’s free, so I’m not complaining. It’s an invaluable read if you’re interested in this new framework.

(legalese)

Tagged with:
Posted in Flash

Two FLVPlayers battle eachother with full-screen

When an FLVPlayer component contains a fullscreen button, whenever the application goes to full-screen, the component automatically shows the FLVPlayer component, even if you have set up an alternative full-screen button elsewhere. The way to prevent the component from hijacking fullscreen operations is by setting the ‘fullScreenTakeOver’ property to false:
video.fullScreenTakeOver=false;

However, when the user clicks fullscreen on the video component itself, you probably want the video to resize so when your video is relevant, don’t forget to set this property back to true.

The interesting thing is that when there are two videos in an application, only one of them wins out as the dominant take-over component, so therefore when you click full-screen on the other component, you actually see the dominant player’s video go full-screen. So, when you have two FLVPlayers in different sections, be sure that only the current FLVPlayer has ‘fullScreenTakeOver’ set to true.

Tagged with: , ,
Posted in Flash

Warning: All instances will be automatically declared as…

Sometimes it’s useful to have two Flash symbols which use the same Base Class which references symbols within the clip, that could be differently symbols. For example, a symbol of base class ‘Menu’ could contains symbols, of base class ‘menuItem’. You might want this to occur in two symbols, ‘MainMenu’ and ‘SubMenu’ which reuse the same ‘Menu’ class for reuse, because they contain exactly the same functionality.i.e.:

the movieClip MainMenu, has the base class Menu

the movieClip SubMenu has the base class Menu

However, you’ll encounter a warning:

Warning: All instances named ‘xxx’ will be automatically declared as xxx in symbols that use xxx as their base class. In symbols that are linked to user-defined base classes, instances with the same name must be of the same type.

In our example, all items called ‘menuItem1’ within the ‘menu’ class will all be visually the same, because their class is assumed to be the same.

Now googling this problem seems to result in only one possible solution, to uncheck ‘Automatically declare stage instances’ in the advanced actionscript 3.0 settings, but really this makes life more difficult in other areas. There are also calls for Adobe to automatically declare instances as the base class rather than the super class, but I believe this would introduce other problems, as the symbols contained in the superclass would not be available.

My solution is probably obvious to some, but here it is. To avoid Flash automatically declaring the instance as the superclass and therefore typing all symbols the same, we just need to create a simple unique base class for each unique symbol that extends our class. This is a little confusing to explain, so to return to the example:

the symbol MainMenu, has the base class MainMenu, which just extends the ‘Menu’ class.

the symbol SubMenu, has the base class SubMenu, which just extends the ‘Menu’ class.

This way the menu items are not automatically typed to be the same symbol.

Tagged with: ,
Posted in Flash