iPad says hello to Flash community

Hello iPad. Maybe Apple denied compiling Apps with Flash because they just had problems delivering enough iPads to the Flash community? đŸ˜‰

Since customer requests grow and a new version of iPad seems to appear on the horizon I decided to get one of the 1. gen. iPads for testing purposes. I’m looking forward developing parallel solutions for the web and the iPad / iPhone and I see myself fighting against system limitations like the old days where we had to test our Flash 4 projects on PCs much slower than current mobile devices.

Ride it baby!

Flash Performance Visualizer

Mr.doop’s Hi-ReS! Stats is a must have for every ActionScript developer. Seems to be still no. 1!
And I don’t want to search again… So here just the links:

Mr.doop’s blog | Hi-ReS! Stats
Mr.doop’s Stats.as @ GitHub

Update – Most recent version I found:
http://code.google.com/p/mrdoob/source/browse/trunk/libs/net/hires/debug/Stats.as

Undocumented XMLUtil class in Adobe Flash CS5?

I tried to recompile an older Flash CS 4 project with Flash CS 5 but got this compile time error 1061: Call to a possibly undefined method reuseNodes through a reference with static type Class caused by the usage of one of my utility classes:

This didn’t work

import de.superclass.util.XMLUtil;
...
XMLUtil.someMethod();

This still works

...de.superclass.util.XMLUtil.someMethod();

So there was no error in my class because it’s still usable when I use the full class package but it didn’t work when I just import it with the import statement.

After some research I found an undocumented XMLUtil class which avoids the correct access to my de.superclass.util.XMLUtil class.

This class doesn’t exist in Flash CS 4 but is available in Flash CS 5. Simply create a new FLA in Flash CS 5 an run this code on timeline

trace( describeType( XMLUtil ) );

and you’ll get this result:

<type name="XMLUtil" base="Class" isDynamic="true" isFinal="true" isStatic="true">
  <extendsClass type="Class"/>
  <extendsClass type="Object"/>
  <constant name="kAttrYMin" type="String"/>
  <constant name="kAttrXMax" type="String"/>
  <constant name="kAttrYMax" type="String"/>
  <constant name="kAttrObj0" type="String"/>
  <constant name="kAttrObj1" type="String"/>
  <constant name="kAttrX0" type="String"/>
  <constant name="kAttrY0" type="String"/>
  <constant name="kAttrX1" type="String"/>
  <variable name="kTagGravity" type="String"/>
  <constant name="kAttrY1" type="String"/>
  <variable name="kTagCollideSpace" type="String"/>
  <constant name="kAttrType" type="String"/>
  <variable name="kTagRigidBody" type="String"/>
  <constant name="kAttrPin" type="String"/>
  <variable name="kTagRect" type="String"/>
  <constant name="kAttrSlider" type="String"/>
  <variable name="kTagJoint" type="String"/>
  <constant name="kAttrLength" type="String"/>
  <variable name="kTagSpring" type="String"/>
  <constant name="kAttrStrength" type="String"/>
  <variable name="kTagFrames" type="String"/>
  <constant name="kAttrDamping" type="String"/>
  <variable name="kTagFrame" type="String"/>
  <constant name="kAttrSimSpeed" type="String"/>
  <variable name="kTagFluid" type="String"/>
  <constant name="kAttrAxis" type="String"/>
  <variable name="kTagEmitter" type="String"/>
  <constant name="kAttrAsset" type="String"/>
  <variable name="kTagOrigin" type="String"/>
  <constant name="kAttrSpring" type="String"/>
  <variable name="kTagKeyframes" type="String"/>
  <constant name="kAttrSpringStrength" type="String"/>
  <variable name="kTagKey" type="String"/>
  <constant name="kAttrSpringDamping" type="String"/>
  <variable name="kTagView" type="String"/>
  <variable name="kTagGeom" type="String"/>
  <constant name="kAttrIndex" type="String"/>
  <constant name="kAttrCollideType" type="String"/>
  <constant name="kAttrCellSize" type="String"/>
  <constant name="kAttrSpringValue" type="String"/>
  <constant name="kAttrCollideSpace" type="String"/>
  <constant name="kAttrRowDimen" type="String"/>
  <constant name="kAttrDensity" type="String"/>
  <constant name="kAttrColDimen" type="String"/>
  <constant name="kAttrPosX" type="String"/>
  <constant name="kAttrTimeStep" type="String"/>
  <constant name="kAttrPosY" type="String"/>
  <constant name="kAttrTime" type="String"/>
  <constant name="kAttrAngle" type="String"/>
  <constant name="kAttrColor" type="String"/>
  <constant name="kAttrVelX" type="String"/>
  <constant name="kAttrStrokeColor" type="String"/>
  <constant name="kAttrVelY" type="String"/>
  <constant name="kAttrAlpha" type="String"/>
  <constant name="kAttrVelA" type="String"/>
  <constant name="kAttrFPS" type="String"/>
  <constant name="kAttrCOR" type="String"/>
  <constant name="kAttrSprings" type="String"/>
  <constant name="kAttrCOF" type="String"/>
  <constant name="kAttrLimits" type="String"/>
  <constant name="kAttrFixed" type="String"/>
  <constant name="kAttrMinAngle" type="String"/>
  <constant name="kAttrID" type="String"/>
  <constant name="kAttrDBlend" type="String"/>
  <constant name="kAttrPoseStrength" type="String"/>
  <constant name="kAttrPoseDamping" type="String"/>
  <constant name="kAttrBodyDamping" type="String"/>
  <constant name="kAttrX" type="String"/>
  <constant name="kAttrY" type="String"/>
  <constant name="kAttrXMin" type="String"/>
  <accessor name="prototype" access="readonly" type="*" declaredBy="Class"/>
  <method name="nodeHasAttribute" declaredBy="XMLUtil" returnType="Boolean">
    <parameter index="1" type="XML" optional="false"/>
    <parameter index="2" type="String" optional="false"/>
  </method>
  <method name="getIntAttribute" declaredBy="XMLUtil" returnType="int">
    <parameter index="1" type="XML" optional="false"/>
    <parameter index="2" type="String" optional="false"/>
    <parameter index="3" type="int" optional="true"/>
  </method>
  <method name="getNumberAttribute" declaredBy="XMLUtil" returnType="Number">
    <parameter index="1" type="XML" optional="false"/>
    <parameter index="2" type="String" optional="false"/>
    <parameter index="3" type="Number" optional="true"/>
  </method>
  <method name="getBoolAttribute" declaredBy="XMLUtil" returnType="Boolean">
    <parameter index="1" type="XML" optional="false"/>
    <parameter index="2" type="String" optional="false"/>
    <parameter index="3" type="Boolean" optional="true"/>
  </method>
  <method name="getStringAttribute" declaredBy="XMLUtil" returnType="String">
    <parameter index="1" type="XML" optional="false"/>
    <parameter index="2" type="String" optional="false"/>
    <parameter index="3" type="String" optional="true"/>
  </method>
  <factory type="XMLUtil">
    <extendsClass type="Object"/>
  </factory>
</type>

So I had to rename my class to de.superclass.util.XMLUtils.

You might run into the same problems when using mx.utils.XMLUtil (Flex Framework) or com.adobe.utils.XMLUtil (AS3CoreLib) but I didn’t test it!

UPDATE:
I found XMLUtil classes in
Adobe Flash CS5/Common/Configuration/ActionScript 3.0/libs/ik.swc and
Adobe Flash CS5/Common/Configuration/ActionScript 3.0/libs/PffLib.swc

Removing the $(AppConfig)/ActionScript 3.0/libs directory within the ActionScript export settings avoids the problem. But I have no time to test if this directory is necessary. If you run into problems please leave me a comment!

Aligning Flash TextField instances visually correct

I was looking for an easy way to align TextField instances with different font sizes visually correct. I really thought this wouldn’t take much time but it turned out to become really frustrating.

So think about a simple scenario: Try to align two TextField instances with different font sizes side by side. If you just set the TextField.y property to the same value you will recognise that different font sizes have different top margins. Well, you might fix that by hand if you have a static layout but what if you don’t know what kind of Text will be displayed? In my case I needed to align text always on top with the same margin regardless of the headline font size.

I tried hard to get this done by using different methods provided by the TextField class. Then I tried to work with the TextLineMetrics class as well. Nothing worked properly for me. I needed to work with CSS formatted HTML text so I was looking for a margin-top style or something similar. Not available. Hm.

Then I remembered my solution about finding the alpha bounds within external loaded PNG files and used that. Well, the main downside is that I need to create a BitmapData instance to determine the exact text bounds but otherwise it worked out very well.

It all comes down to two simple methods that will slip into my library. At the end you will receive a rectangle representing the bounds on the TextField instance.

If you know a different way to obtain the same exact result please leave me a comment!

Here’s my solution:

function getDisplayObjectAlphaBounds( displayObject : DisplayObject, smoothing : Boolean = true ) : Rectangle
{
	var bitmapData : BitmapData = new BitmapData( displayObject.width, displayObject.height, true, 0 );
		bitmapData.draw( displayObject, null, null, null, null, smoothing );
 
	var alphaBounds : Rectangle = bitmapData.getColorBoundsRect( 0x01000000, 0x01000000 );
 
	bitmapData.dispose();
 
	return alphaBounds;
}
 
function getTextFieldTextBounds( textField : TextField, smoothing : Boolean = true ) : Rectangle
{
	var background : Boolean = textField.background;
	var backgroundColor : uint = textField.backgroundColor;
	var border : Boolean = textField.border;
	var borderColor : uint = textField.borderColor;
	var opaqueBackground : Object = textField.opaqueBackground;
 
	textField.background = false;
	textField.border = false;
	opaqueBackground = null;
 
	var textBounds : Rectangle = getDisplayObjectAlphaBounds( textField, smoothing );
 
	textField.background = background;
	textField.backgroundColor = backgroundColor;
	textField.border = border;
	textField.borderColor = borderColor;
	textField.opaqueBackground = opaqueBackground;
 
	return textBounds;
}
 
var textFormat : TextFormat = new TextFormat();
	textFormat.align = TextFormatAlign.CENTER;
	textFormat.color = 0x0000FF;
	textFormat.font = "Arial";
	textFormat.size = 30;
 
var textField : TextField = new TextField();
	textField.border = true;
	textField.borderColor = 0x0000FF;
	textField.background = true;
	textField.backgroundColor = 0x000022;
	textField.defaultTextFormat = textFormat;
	textField.height = 260;
	textField.text = "\nThis text\ncan be\naligned\nproperly!";
	textField.width = 300;
	textField.x = 30;
	textField.y = 30;
 
addChild( textField );
 
// Get bounds
var textBounds : Rectangle = getTextFieldTextBounds( textField );
 
// Draw bounds
var shape : Shape = new Shape();
	shape.x = textField.x;
	shape.y = textField.y;
 
var g : Graphics = shape.graphics;
	g.lineStyle( 1, 0x00FFFF );
	g.drawRect( textBounds.x, textBounds.y, textBounds.width, textBounds.height );
 
addChild( shape );

Setting up my new MacBook Pro

A few days ago my new my new antiglare 15″ i7 MacBook Pro arrived and I decided to manually setup this new system. Rethinking everything is always a good opportunity to leave some old stuff behind.

Before I bought my first MacBook Pro in late 2006 I owned PCs only and so I still used Thunderbird on my Mac until now. But it wasn’t that easy to bring all my old local stored mails into Mail. It worked quite well but for some reasons it didn’t work for every folder. For example one folder contained 2364 emails but Mail was only importing 653. I tried it several times but I had to use my IMAP account to transfer these mails into this new environment. That took really a little while for several folders.

Maybe it’s not necessary but since my new user account uses the same username and password I had no problem to simply copy & paste data for Adium, Address Book, iCal, iPhoto, iTunes and Skype.

I also decided to upgrade or switch to newer software like OmniFocus, Parallels Desktop 5, Transmit and Versions. And of course a fresh version of FDT Enterprise is still my favorite application.

Luckily Adobe shipped the new Creative Suite 5 today and so hopefully there’s no need to install CS 4 products anymore.

My last step is refining my directory structure and then I’m looking forward to work with this machine for the next 3 or 4 years with hardware video encoding and 8 GB RAM.

But the biggest question is: Which sticker will I use to hide the big apple?

Update – 2011.09.15. Finally I made a decision:

FFK10 – Flashforum conference notes

Every year I spend two days sitting in the audience of the Flashforum conference (FFK) listening to great speakers and getting impressed by their experiments and thoughts. It’s also a good way to renew some of the basic knowledge in Flash development and of course to meet some friends in the Flash scene.

So this are most of my notes:

Flash / Flex development:

  • Jessee Freemans Flash Augmented Reality Debug Tool provides an easy way to start with augmented reality development.
  • Use stunning Hype-Framework effects.
  • Dive into dynamic sound generation with AndrĂ© Michelles Audio-Sandbox.
  • Have a look at the PushButton-Engine for component based development.
  • Remember that Flex 4 includes a lot of performance features! It’s highly recommended to switch as soon as possible. For example the Embed-tag reduces PNG file size and lots of improvements are made within the Flex components.
  • Watch the Adobe TV video preview: Flex for mobile devices
  • See Christian Cantrell’s blogpost One Application , Five Screens (Including the iPad)
  • Great tip: ByteArray.org – Why cacheAsBitmap is bad
  • Adobe’s Mobile Development Guide for the Flash platform (applies also to desktop applications) contains performance tips like:

    • DisplayObject.width / height should be divisible by 2 as often as possible
    • Try to avoid Events and / or stop propagation as soon as possible
    • Set DisplayObject.mouseEnabled=false if possible
    • Stop MovieClip animations when removed from stage
    • Use TextField.opaqueBackground=true if possible
    • Use final statement (final class ClassName {})
    • Use BitmapData.get / setVector()

HTML / JavaScript basics:

  • Use “Sprites” with HTML / CSS (load only one bitmap graphic containing all the asset images for your page and show only the particular relevant parts) and preload next page assets using AJAX while your current page is idle.
  • Since usually only 2 simultaneous domain http requests are supported by browsers it’s a good practice to distribute contents from various ip addresses (use asset-servers for example).
  • Load only visible parts of your site using JavaScript viewport events.

Useful workflow utils:

Embed fonts with Adobe Flash IDE

Almost every Flash project needs some embedded fonts and it is a good practice to compile the fonts into a separate SWF file. So here is a simple way to create a file that contains only embedded fonts. The SWF file will also show the exact internal font names:

  1. Copy and paste the ActionScript code below into the first keyframe of your timeline.
  2. Create new fonts in flash library and export them for ActionScript.
    A good tutorial can be found here.
  3. Run ONLY the code for step 2 to evalute and trace the exact font names.
  4. Assign the exact font names to the actual library symbols and their export class name.
  5. Run ONLY the code for step 4 to export the swf.
Security.allowDomain( "*" );
 
// Step 1: Create new fonts in flash library
//         and select "Export for ActionScript".
 
 
// Step 2: Run ONLY this code to evalute and trace the exact font names.
/**/
var embeddedFonts : Array = Font.enumerateFonts ( false );
var c : uint = embeddedFonts.length;
for ( var i : uint = 0; i < c; i++ )
{
	var font : Font = embeddedFonts[ i ] as Font;
	var className : String = font.fontName.split( " " ).join( "" );
 
	var lowerFontStyle : String = font.fontStyle.toLowerCase();
	if ( lowerFontStyle.indexOf( "bold" ) != -1 ) className += "Bold";
	if ( lowerFontStyle.indexOf( "italic" ) != -1 ) className += "Italic";
 
	trace( className );
}
/**/
 
// Step 3: Assign the exact font names to the actual
//         library symbols and their export class name.
 
 
// Step 4: Export the swf using ONLY this code. 
/**/
var posX : int = 10;
var posY : int = 10;
 
var embeddedFonts : Array = Font.enumerateFonts ( false );
	embeddedFonts.sortOn( "fontName", Array.CASEINSENSITIVE );
 
var c : uint = embeddedFonts.length;
for ( var i : uint = 0; i < c; i++ )
{
	var font : Font = embeddedFonts[ i ] as Font;
 
	var lowerFontStyle : String = font.fontStyle.toLowerCase();
 
	var textFormat : TextFormat = new TextFormat();
		textFormat.bold = ( lowerFontStyle.indexOf( "bold" ) != -1 );
		textFormat.italic = ( lowerFontStyle.indexOf( "italic" ) != -1 );
		textFormat.font = font.fontName;
		textFormat.size = 14;
 
	var className : String = font.fontName.split( " " ).join( "" );
	if ( textFormat.bold ) className += "Bold";
	if ( textFormat.italic ) className += "Italic";
 
	Font.registerFont( Class( getDefinitionByName( className ) ) );
 
	var boldItalic : String = "";
	if ( textFormat.bold && textFormat.italic )
	{
		boldItalic = "( needs to be BOLD and ITALIC ! )";
	}
	else if ( textFormat.bold )
	{
		boldItalic = "( needs to be BOLD ! )";
	}
	else if ( textFormat.italic )
	{
		boldItalic = "( needs to be ITALIC ! )";
	}
 
	var textField : TextField = new TextField();
		textField.autoSize = TextFieldAutoSize.LEFT;
		textField.defaultTextFormat = textFormat;
		textField.embedFonts = true;
		textField.text = font.fontName + "\t" + boldItalic;
		textField.x = posX;
		textField.y = posY;
 
	posY += textField.height + 5;
 
	addChild( textField );
}
/**/