Posts Tagged ‘Script’

05
Feb

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.

Tags: , , ,