va.lent.in — what a flash developer’s site should be

valentin

A couple of weeks ago I released my new personal portfolio/sandbox site — va.lent.in. I need more opinions and less bug reports.

I like projects which make me learn something. During this one I learned a lot…

Continue reading ‘va.lent.in — what a flash developer’s site should be’

AS3 is weird. True story!

Well, every experienced AS3 developer once in a while faces weird things in our beloved ActionScript 3. Sometimes it’s funny but usually it isn’t, because results in hours of wasted time. Blooddy, my Belorussian friend, compiled some of the obstacles he faced in the past into the series of short microblog posts. In this post I’ll try to translate those posts in English adding my own experience.

OK, I don’t know where to start, so the order here means nothing. Let’s start.

1. LOL! ME BROKED TEH FLASH VERIFEIRZ!!!

for ( 	var i:uint = reversed ? array.length-1 : 0;
    reversed ? i >= 0 : i < array.length;
    reversed ? i-- : i++ ) {
}

This code compiles perfectly but results in a huge bytecode dump and a weird error — VerifyError: Error #1030: Stack depth is unbalanced. 1 != 0.

Don’t ask me how I got to this code.

2. Object vs. Object

var a:Object = {};
a["a"] = 1;
a["b"] = 2;
a["c"] = 3;
for ( var v:String in a ) {
    a["a"] = 2;
    trace(v, a[v]);
}

How do you think what this code will result into? You would guess something like

a 2
b 2
c 3

But it’s actually

a 2
a 2
c 3

for me.

If you change the first line to

var a:Object = new Object();

you’ll get

b 2
a 2
c 3

Of course Adobe didn’t promise order in collections which Objects are. Also, modifying a collection while working with it looks wrong anyway. But how come new Object() and {} differ so much, as far as I remember everyone says that both these constructs create an object, the later one just can handler properties to set. Apparently it’s not right.

Actually {} results into just one opcode NewObject while new Object() results in 2 opcodes: look for class, create class (sorry, will change for actual opcode names later). Anyway, you should be aware of this fact.

3. Where did this Security Error came from?

Imagine that we have a Socket object. We want to connect to some server but it’s down. We got IO Error and want to remove all listeners from Socket events and BOOOOM! we get a Security Error because Flash couldn’t get socket policy file (undoubtedly).

Who knew that right after IO Error we’ll get a Security Error?

4. Who called this .load() ?

Imagine we have a class extending Sound.

public class S extends Sound {
  public function S() {
    super();
  }
  public override function load(stream:URLRequest, context:SoundLoaderContext=null):void {
    throw new Error( 'ZOMG PEW PEW!!!1' );
  }
}

How do you think, what will we get after executing var s:S = new S(); ?

Right, we’ll get ZOMG PEW PEW!!!1 because despite of Flash help saying “If you pass a valid URLRequest object to the Sound constructor, the constructor automatically calls the load() function for the Sound object.”, constructor actually calls .load() anyway.

5. Super()? What super()?

Continuing #4, what if we could block parent constructor of being executed… But we can’t, if you don’t specify super() call compiler will add it automatically. Well, we could add it somewhere where it won’t be executed.

if ( false ) {
  super();
}

But damn, compiler is smart. But not so smart to overcome this:

if ( !true ) {
  super();
}

Or it knows something we don’t! Apparently !true isn’t always false. But we can skip executing super constructor until Adobe fixes it.

6. GET MY CHILD BACK YOU BIATCH!!!

Imagine that we have a Container extends DisplayObjectContainer which overrides removeChild() method to throw exception so bad people couldn’t remove children from it.

Let child:DisplayObject be a child of container:Container, now look at the code

var s:Sprite = new Sprite();
s.addChild( child );
s.removeChild( child );

Apparently, it bypasses our overridden method and STEALS OUR CHILD!!!!1

7. Wait, so many loaders… I’m confused…

All the time we use loaders of different kinds: Loader, Sound, URLLoader, URLStream, FileReference. So why are they so different?

1. Loader.

  • First of all it extends DisplayObject, maybe that’s why everything loading related is in contentLoaderInfo (this is what makes me mad every time).
  • load(request:URLRequest, context:LoaderContext = null):void
  • bytesLoaded:uint (read-only)
  • bytesTotal:uint (read-only)
  • url:String (read-only)

2. Sound.

  • load(stream:URLRequest, context:SoundLoaderContext = null):void
  • bytesLoaded:uint (read-only)
  • bytesTotal:int (read-only)
  • url:String (read-only)
  • Doesn’t have httpStatus event

3. URLLoader.

  • load(request:URLRequest):void
  • bytesLoaded:uint (read-write)
  • bytesTotal:uint (read-write)
  • Also, why all URLLoader’s properties are public variables not accessors?

4. URLStream.

  • load(request:URLRequest):void
  • No bytesLoaded or bytesTotal, but at least we get a progress event

5. FileReference.

  • We get 3 methods to load data: load, download, upload
  • No bytesLoaded or bytesTotal, but at least we get a progress event

And last, ProgressEvent has properties bytesLoaded (read-write) and bytesTotal (read-write). Both of type NUMBER.

So if you want to implement your own universal loader you must know all these differences.

8. Missing TextField.

Flash says that inheritance chain for TextField is the following: TextField -> InteraftiveObject -> DisplayObject -> EventDispatcher -> Object. Apparently there’s DisplayObjectContainer missing because we can do the following:

public function test() {
  var t:TextField = new TextField();
  t.addEventListener( Event.ADDED, this.handler_addedToStage )
  t.width = 400;
  t.height = 200;
  t.htmlText = ' <img src="http://www.google.ru/logos/olympics10-hockey-hp.png" />';
  super.addChild( t );
}
private function handler_addedToStage(event:Event):void {
  if ( event.target == event.currentTarget ) return;
  trace( event.target );
}

The code results in

[object Loader]
[object Sprite]

It means that we can grab Loaders for HTML images and preload them. Also we can reparent them using the trick above (8

9. Hi, I am addedToStage! Hi, I am addedToStage!

Here’s the code:

public function test() {
  var s1:Sprite = new Sprite();
  s1.addEventListener( Event.ADDED_TO_STAGE, handler );
  super.addChild( s1 );
}

private function handler(event:Event):void {
  var s2:Sprite = new Sprite();
  s2.addEventListener( Event.ADDED_TO_STAGE, trace );
  ( event.target as Sprite ).addChild( s2 );
}

Do you expect to see only one trace? Nope, you’ll get TWO!

And here’s why. We know that addedToStage event is dispatched in the addChild() method. After executing it must tell all children that they were added to stage too. So, when we add a new object to display list in handler() it first gets its own event and after that execution flow returns back to super.addChild() where it tells all its children about them being added to stage. And there’s where the second event comes from.

Of course if we add more children objects we’ll get more misleading events.

10. __AS3__.vec

The Vector class is kind of mysterious. Flash help says that it is top level class but actually it relies in virtual package __AS3__.vec which doesn’t actually exists but is made by compiler.

Looks like a patch which is there since some early beta of Flash Player 10.

HOORAY!

That’s all for now. If you have something to add to the list feel free to mail me or leave a comment here.

Do you still want to work at Zynga?

redbull

Zynga is the most rapidly growing social gaming company in the world. But looks like if you want to work there you will have to work hard. I wonder how much they pay senior flash developers.

The comic about me

… at my new job.

6a00d8341d3df553ef0120a8b38156970b-800wi

via

Jobs was right. Flash does kill Macs after all.

flash_kernel_panic

Just witnessed this situation. True story.

ZOMG! Signals strike again!!!!1

Checked out TurboSignals by Jackson Dunstan today. Please stop sending me this link over and over again.

I see a lot of people don’t understand the point. “ZOMG IT’S ZILLION TIMES FASTER I MUST USE IT EVERYWHERE!!!!1″. No you don’t. Everything should be used where it fits. I saw a lot of people started using architectural frameworks like PureMVC or Swiz without understanding the theory behind them. Thus inventing hacks to overcome framework “constraints” while what they see as “constraints” come from their lack of knowledge.

A lot of people think that if something is advertised as being good and fast they must use it in their projects. STOP NOW! Think first if you really need all this stuff.

Same here. I am absolutely happy with Events and I love all sort of bubbling. Events are good for UIs and tree-like structures. I don’t have to reinvent the wheel. I just work with events everywhere in the same manner.

BUT! If I need greater performance somewhere in critical code chunks I’m using simple function calls. I know that I create obvious dependencies but I do it where it makes sense. You should not rush to change Events to Signals or whatever everywhere. Inventing hacks and making your app impossible to maintain.

Check out TurboSignals sources, there are like 20 lines of code which do stuff. You could implement such interface-based notifying yourself.

What you really should do is to read the whole Jackson’s blog. You’ll find a lot of information about AS3 optimization and stuff. Good job, man!

MediaTemple rocks!

Since when they give 100Gbs of space? I was sure I had a 1Gb limit. I almost started deleting big files to fit my podcast episodes when I decided to check how much they charge for extra space. And I was surprised to see that the limit is 100Gbs!

Great image distortion idea

Recently I wrote about my distortion effect. Believe me, I experimented with it a lot. And it was damn slow on big bitmaps. But here’s a funny way to do it through native jpeg decoding. And it runs smooth on relatively big bitmaps. The guy messes up with jpeg data in ByteArray many times in a row loading it over and over again. Letting Flash native jpeg decoder do the work for him. This is is a great example of creative thinking!

The power of JSFL

When you want to automate boring repetitive actions in Flash IDE, JSFL is your best friend. It’s basically AS1 for working with FLA contents. Recently I had to dig deeper in JSFL and here are the results.

(0,0) and transformation point.

Flash animators made lots of character animations for a new game. All character’s parts will be replaced in game engine with skinned ones for different characters. But animation stays the same, so essentially an animation is a bunch of moving empty MovieClips where skins will be added later. The problem was that they used Flash IDE transformation point not in anchor (0,0) point. I couldn’t find any reference to that magic point in AS3 help, so people would have to move all parts in all animations and symbols in each part manually. That looks like a very time consuming process. So I opened JSFL help and wrote this:

function run() {
	var hash = {};

	var items = fl.getDocumentDOM().library.getSelectedItems();
	for ( var u = 0; u < items.length; u++ ) {
		var item = items[u];
		var layers = item.timeline.layers.length;
		for ( var i = 0; i < layers; i++ ) {
			var frames = item.timeline.layers[i].frames.length;
			for ( var j = 0; j < frames; j++ ) {
				var element = item.timeline.layers[i].frames[j].elements[0];
				if ( element && element.libraryItem != undefined ) {
					if ( !hash[element.libraryItem.name] ) {
						hash[element.libraryItem.name] = element.getTransformationPoint();
					}
					element.x = element.transformX;
					element.y = element.transformY;
					element.setTransformationPoint({x:0, y:0});
				}
			}
		}
	}

	for ( var i = 0; i < fl.getDocumentDOM().library.items.length; i++ ) {
		var item = fl.getDocumentDOM().library.items[i];
		if ( hash[item.name] ) {
			var timeline = item.timeline;
			for ( var l = 0; l < timeline.layers.length; l++ ) {
				for ( var m = 0; m < timeline.layers[l].frames[0].elements.length; m++ ) {
					var insideElement = timeline.layers[l].frames[0].elements[m];
					insideElement.x -= hash[item.name].x;
					insideElement.y -= hash[item.name].y;
				}
			}
			delete hash[item.name];
		}
	}

}

run();

The script moves all body parts in all selected library animations to make transformation point and anchor point match and after that moves body parts’ inner graphics accordingly. First, it creates a hash of body parts not to move their content several times resulting in broken animation. After, it iterates through selected library symbols, their layers and frames, adds all instances of library symbols to the hash, moves them to (transformX, transformY) and resets transformation points. The next loop just moves inner content in separate direction by the same distance.

Problem solved! Spend 30 minutes to read manuals and 20 minutes to write actual code but saved several days of animators’ work.

Add names to MovieClips in named layers.

The next task was to add instance names to empty MovieClips in animations. Thanks God all layers with body parts were named uniformly everywhere. Here’s the code:

function run() {
	var map = {	hand_R_anim: "p04",
				leg_R_anim: "p06",
				foot_R_anim: "p08",
				head_anim: "p01",
				body_anim: "p02",
				leg_L_anim: "p05",
				foot_L_anim: "p07",
				hand_L_anim: "p03"
			};

	var items = fl.getDocumentDOM().library.getSelectedItems();
	for ( var u = 0; u < items.length; u++ ) {
		var item = items[u];
		var timeline = item.timeline;
		var layers = timeline.layers;
		for ( var i = 0; i < layers.length; i++ ) {
			var layer = layers[i];
			var name = map[layer.name];
			if ( name ) {
				for ( var j = 0; j < layer.frames.length; j++ ) {
					var element = layer.frames[j].elements[0];
					if ( element ) {
						element.name = name;
					}
				}
			}
		}
	}
}

run();

Split legs and feet.

And the last task was to split legs and feet animations because they should have been separate body parts but were drawn and animated as one MovieClip everywhere.

function run() {
	var path = "1/anim/";

	var items = fl.getDocumentDOM().library.getSelectedItems();
	for ( var u = 0; u < items.length; u++ ) {
		var item = items[u];
		var timeline = item.timeline;
		var layers = timeline.layers;
		var layerR = 0;
		var layerL = 0

		for ( var i = 0; i < layers.length; i++ ) {
			if ( layers[i].name == "foot_R_anim" ) layerR = i;
		}
		timeline.setSelectedLayers(layerR);
		timeline.copyFrames(0, layers[layerR].frameCount);
		var created = timeline.addNewLayer( "leg_R_anim" );
		timeline.setSelectedLayers(created);
		timeline.pasteFrames();
		for ( var i = 0; i < layers[created].frameCount; i++ ) {
			var element = layers[created].frames[i].elements[0];
			if ( element && element.libraryItem.name == path + "foot_R_anim" ) {
				element.libraryItem = fl.getDocumentDOM().library.items[fl.getDocumentDOM().library.findItemIndex(path + "leg_R_anim")];
			}
		}

		layers = timeline.layers;
		for ( var i = 0; i < layers.length; i++ ) {
			if ( layers[i].name == "foot_L_anim" ) layerL = i;
		}
		timeline.setSelectedLayers(layerL);
		timeline.copyFrames(0, layers[layerL].frameCount);
		var created = timeline.addNewLayer( "leg_L_anim" );
		timeline.setSelectedLayers(created);
		timeline.pasteFrames();
		for ( var i = 0; i < layers[created].frameCount; i++ ) {
			var element = layers[created].frames[i].elements[0];
			if ( element && element.libraryItem.name == path + "foot_L_anim" ) {
				element.libraryItem = fl.getDocumentDOM().library.items[fl.getDocumentDOM().library.findItemIndex(path + "leg_L_anim")];
			}
		}
	}
}

run();

Here we once again take selected items in library. Path variable is the folder with body parts. First we look for the needed layer number, select frames, copy and paste them to a new layer. After that we iterate through frames and existing instances to be of another symbols. We do it 2 times for both legs.

Good AS2 programmers are so rare these days

Who would expect it to be so hard to find a good ActionScript 2 (yes, ActionScript TWO) developer these days. Our company’s main project is a big flash MMO written in AS2 long time ago. It is still popular and brings a lot of money. But people come and go, so live team department is looking for an AS2 programmer without success so far.

There’re just no AS2 developers left. And that’s obvious why. You either go mainstream (if you are decent) and learn AS3 or work for a company coding banners in frame scripts (if you are bad or don’t want to learn). Nobody stays long (if at all) in AS2 world these days. As it has been so far, people who claim to know AS2 are just bad. They don’t know AS2, they know just a bit of programming. No OOP or design patterns. I’m not saying that AS2 can be tricky sometimes and you have to be good to support a large-scale project.

Personally, I should not mention AS2 knowledge in my resume because I totally forgot it. And don’t really want to return back to those days. But if offered 2x payment raise I’d think about it.

Parsing PDFs

Why do people keep making libraries which can only CREATE pdf files? I want one which can parse pdfs and export text/images with layout.