Jau*_*ika 3 flash actionscript-3
我已经将Adobe Illustrator文档中的许多路径导入到Flash文件中.路径在场景中作为绘图对象存在.使用纯动作脚本,如何在不使用预定义动作参考线的情况下在每条线后移动符号.
编辑:我附加了Flash文件,充满了绘图对象.
http://rapidshare.com/files/406497264/pather.fla.html
问题是:这些绘图对象是否可以通过AS3访问,或者我应该将它们转换为符号/任何必要的格式.请举几个AS示例.
谢谢!
Nice question +1
I've seen the fla at work, don't have cs5 home, but I understand what you're trying to achieve.
My approaches were these:
Since Flash CS4 you can copy a path, and paste it onto a Motion Tween. This will work similar to the Classic Tween's Motion Guide feature. There are quite a few problems with this:
Obviously this is a no-no.
Using JSFL to traverse the paths inside the IDE:
I stumbled upon this very handy jsfl script by ericlin which traverses all shapes selected on stage. If you select your paths and run the script(you can just double click the jsfl file), you will get the parsed coordinates.
I did a simple test using TweenLite:
import com.greensock.*;
import com.greensock.easing.*;
import com.greensock.plugins.*;
TweenPlugin.activate([BezierPlugin]);
graphics.lineStyle(0.05);
var index:int = 0;
var ball:Sprite = new Sprite();
ball.graphics.beginFill(0x009900,.75);ball.graphics.drawCircle(-2,-2,4);ball.graphics.endFill();
addChild(ball);
drawLines();
function drawLines():void{
var t:Number = .01;
var timeline:TimelineLite = new TimelineLite();
var i:int = index;
for(index; index <= ptArray.length; index += 12){
timeline.append( new TweenLite(ball, t, {x:ptArray[i],y:ptArray[i+1]}) );
timeline.append( new TweenLite(ball, t, {bezier:[{x:ptArray[i+2], y:ptArray[i+3]}, {x:ptArray[i+4], y:ptArray[i+5]}]}) );
this.graphics.moveTo(ptArray[i], ptArray[i+1]);
this.graphics.curveTo(ptArray[i+2], ptArray[i+3], ptArray[i+4], ptArray[i+5]);
i += 6;
timeline.append( new TweenLite(ball, t, {x:ptArray[i],y:ptArray[i+1]}) );
timeline.append( new TweenLite(ball, t, {bezier:[{x:ptArray[i+2], y:ptArray[i+3]}, {x:ptArray[i+4], y:ptArray[i+5]}]}) );
this.graphics.moveTo(ptArray[i], ptArray[i+1]);
this.graphics.curveTo(ptArray[i+2], ptArray[i+3], ptArray[i+4], ptArray[i+5]);
}
}
Run Code Online (Sandbox Code Playgroud)
*Note:*The ptArray isn't shown here because it would waste too much space. The result isn't that great though. You can have a look at the fla to see what I mean. The jsfl script could be altered, but I saw you emphasised actionscript usage, so this is a no no as well.
Claus Wahlers developed an amazing as3 library called as3swf which allows flash/flex developers to decompile swfs at runtime. Here is an awesome article explaining the ins and outs of shapes inside swfs. There are quite a few exporters already written.
I just duplicated the AS3ShapeExporter and changed the as3 draw commands to TweenLite code. Basically I replaced moveTo with a fast tween to position, lineTo, to a regular tween and curveTo with a bezier tween. Tween Lite's BezierPlugin luckily used quadratic bezier, just like curveTo does.
Here is the code you will need to paste inside the fla that holds the shapes:
import com.codeazur.as3swf.*;
import com.codeazur.as3swf.tags.*;
import com.codeazur.as3swf.exporters.*;
this.loaderInfo.addEventListener(Event.COMPLETE, completeHandler);
function completeHandler(e:Event):void {
var swf:SWF = new SWF(this.loaderInfo.bytes);//new SWF(URLLoader(e.target).data as ByteArray);
var doc:AS3ShapeTweenLiteExporter = new AS3ShapeTweenLiteExporter(swf,"ball",.01);
// Loop over all tags
for (var i:uint = 0; i < swf.tags.length; i++) {
var tag:ITag = swf.tags[i];
// Check if tag is a DefineShape
if (tag is TagDefineShape) {
// Export shape tween
TagDefineShape(tag).export(doc);
}
}
trace(doc.actionScript);
}
Run Code Online (Sandbox Code Playgroud)
Basically I load the swf, once it's ready, I pass it's bytes to as3swf and use the AS3ShapeTweenLiteExporter to parse shape tags and spit out actionscript. The 3 paramaters I pass to the constructor are : the swf instance, a name for the tween target and a time for each tween.
Here's how my hacked together class looks like:
package com.codeazur.as3swf.exporters
{
import com.codeazur.as3swf.SWF;
import com.codeazur.utils.StringUtils;
import flash.display.CapsStyle;
import flash.display.InterpolationMethod;
import flash.display.JointStyle;
import flash.display.LineScaleMode;
import flash.display.SpreadMethod;
import flash.geom.Matrix;
import com.codeazur.as3swf.exporters.core.DefaultShapeExporter;
public class AS3ShapeTweenLiteExporter extends DefaultShapeExporter
{
protected var _actionScript:String;
protected var _target:String;
protected var _time:Number;
public function AS3ShapeTweenLiteExporter(swf:SWF,target:String,time:Number) {
super(swf);
_target = target;
_time = time;
}
public function get actionScript():String { return _actionScript; }
override public function beginShape():void {
_actionScript = "import com.greensock.*;\rimport com.greensock.plugins.*;\r\rTweenPlugin.activate([BezierPlugin]);\r\rvar shapeTimeline:TimelineLite = new TimelineLite()\r";
}
override public function beginFills():void {
//_actionScript += "// Fills:\rgraphics.lineStyle();\r";
}
override public function beginLines():void {
//_actionScript += "// Lines:\r";
}
override public function beginFill(color:uint, alpha:Number = 1.0):void {
if (alpha != 1.0) {
_actionScript += StringUtils.printf("graphics.beginFill(0x%06x, %f);\r", color, alpha);
} else {
_actionScript += StringUtils.printf("graphics.beginFill(0x%06x);\r", color);
}
}
override public function beginGradientFill(type:String, colors:Array, alphas:Array, ratios:Array, matrix:Matrix = null, spreadMethod:String = SpreadMethod.PAD, interpolationMethod:String = InterpolationMethod.RGB, focalPointRatio:Number = 0):void {
var asMatrix:String = "null";
if (matrix != null) {
asMatrix = "new Matrix(" +
matrix.a + "," +
matrix.b + "," +
matrix.c + "," +
matrix.d + "," +
matrix.tx + "," +
matrix.ty + ")";
}
var asColors:String = "";
for (var i:uint = 0; i < colors.length; i++) {
asColors += StringUtils.printf("0x%06x", colors[i]);
if (i < colors.length - 1) { asColors += ","; }
}
if (focalPointRatio != 0.0) {
_actionScript += StringUtils.printf("graphics.beginGradientFill('%s', [%s], [%s], [%s], %s, '%s', '%s', %s);\r",
type,
asColors,
alphas.join(","),
ratios.join(","),
asMatrix,
spreadMethod,
interpolationMethod,
focalPointRatio.toString());
} else if (interpolationMethod != InterpolationMethod.RGB) {
_actionScript += StringUtils.printf("graphics.beginGradientFill('%s', [%s], [%s], [%s], %s, '%s', '%s'\r);",
type,
asColors,
alphas.join(","),
ratios.join(","),
asMatrix,
spreadMethod,
interpolationMethod);
} else if (spreadMethod != SpreadMethod.PAD) {
_actionScript += StringUtils.printf("graphics.beginGradientFill('%s', [%s], [%s], [%s], %s, '%s');\r",
type,
asColors,
alphas.join(","),
ratios.join(","),
asMatrix,
spreadMethod);
} else if (matrix != null) {
_actionScript += StringUtils.printf("graphics.beginGradientFill('%s', [%s], [%s], [%s], %s);\r",
type,
asColors,
alphas.join(","),
ratios.join(","),
asMatrix);
} else {
_actionScript += StringUtils.printf("graphics.beginGradientFill('%s', [%s], [%s], [%s]);\r",
type,
asColors,
alphas.join(","),
ratios.join(","));
}
}
override public function beginBitmapFill(bitmapId:uint, matrix:Matrix = null, repeat:Boolean = true, smooth:Boolean = false):void {
var asMatrix:String = "null";
if (matrix != null) {
asMatrix = "new Matrix(" +
matrix.a + "," +
matrix.b + "," +
matrix.c + "," +
matrix.d + "," +
matrix.tx + "," +
matrix.ty + ")";
}
if (smooth) {
_actionScript += StringUtils.printf("// graphics.beginBitmapFill(%d, %s, %s, %s);\r", bitmapId, asMatrix, repeat, smooth);
} else if (!repeat) {
_actionScript += StringUtils.printf("// graphics.beginBitmapFill(%d, %s, %s, %s);\r", bitmapId, asMatrix, repeat);
} else {
_actionScript += StringUtils.printf("// graphics.beginBitmapFill(%d, %s, %s, %s);\r", bitmapId, asMatrix);
}
}
override public function endFill():void {
_actionScript += "graphics.endFill();\r";
}
override public function lineStyle(thickness:Number = NaN, color:uint = 0, alpha:Number = 1.0, pixelHinting:Boolean = false, scaleMode:String = LineScaleMode.NORMAL, startCaps:String = null, endCaps:String = null, joints:String = null, miterLimit:Number = 3):void {
/*
if (miterLimit != 3) {
_actionScript += StringUtils.printf("graphics.lineStyle(%f, 0x%06x, %f, %s, %s, %s, %s, %f);\r",
thickness, color, alpha, pixelHinting.toString(),
(scaleMode == null ? "null" : "'" + scaleMode + "'"),
(startCaps == null ? "null" : "'" + startCaps + "'"),
(joints == null ? "null" : "'" + joints + "'"),
miterLimit);
} else if (joints != null && joints != JointStyle.ROUND) {
_actionScript += StringUtils.printf("graphics.lineStyle(%f, 0x%06x, %f, %s, %s, %s, %s);\r",
thickness, color, alpha, pixelHinting.toString(),
(scaleMode == null ? "null" : "'" + scaleMode + "'"),
(startCaps == null ? "null" : "'" + startCaps + "'"),
"'" + joints + "'");
} else if(startCaps != null && startCaps != CapsStyle.ROUND) {
_actionScript += StringUtils.printf("graphics.lineStyle(%f, 0x%06x, %f, %s, %s, %s);\r",
thickness, color, alpha, pixelHinting.toString(),
(scaleMode == null ? "null" : "'" + scaleMode + "'"),
"'" + startCaps + "'");
} else if(scaleMode != LineScaleMode.NORMAL) {
_actionScript += StringUtils.printf("graphics.lineStyle(%f, 0x%06x, %f, %s, %s);\r",
thickness, color, alpha, pixelHinting.toString(),
(scaleMode == null ? "null" : "'" + scaleMode + "'"));
} else if(pixelHinting) {
_actionScript += StringUtils.printf("graphics.lineStyle(%f, 0x%06x, %f, %s);\r",
thickness, color, alpha, pixelHinting.toString());
} else if(alpha != 1.0) {
_actionScript += StringUtils.printf("graphics.lineStyle(%f, 0x%06x, %f);\r", thickness, color, alpha);
} else if(color != 0) {
_actionScript += StringUtils.printf("graphics.lineStyle(%f, 0x%06x);\r", thickness, color);
} else if(!isNaN(thickness)) {
_actionScript += StringUtils.printf("graphics.lineStyle(%f);\r", thickness);
} else {
_actionScript += "graphics.lineStyle();\r";
}
*/
}
override public function moveTo(x:Number, y:Number):void {
//_actionScript += StringUtils.printf("graphics.moveTo(%f, %f);\r", x, y);
//_actionScript += StringUtils.printf(_target+".x = %f;\r"+_target+".y = %f;\r", x, y);
_actionScript += StringUtils.printf("shapeTimeline.append(new TweenLite("+_target+",0.001,{x:%f,y: %f}));\r", x, y);
}
override public function lineTo(x:Number, y:Number):void {
//_actionScript += StringUtils.printf("graphics.lineTo(%f, %f);\r", x, y);
_actionScript += StringUtils.printf("shapeTimeline.append(new TweenLite("+_target+","+_time+",{x:%f,y: %f}));\r", x, y);
}
override public function curveTo(controlX:Number, controlY:Number, anchorX:Number, anchorY:Number):void {
//_actionScript += StringUtils.printf("graphics.curveTo(%f, %f, %f, %f);\r", controlX, controlY, anchorX, anchorY);
_actionScript += StringUtils.printf("shapeTimeline.append(new TweenLite("+_target+","+_time+",{bezier:[{x:%f,y: %f},{x:%f,y: %f}]}));\r", controlX, controlY, anchorX, anchorY);
}
}
}
Run Code Online (Sandbox Code Playgroud)
Once you download as3swf, you need to save this class in the exporter's package. Here is the result. You can download its fla and also the fla for that generated the code.
This is a pure actionscript version and has decent result.
The animation looks jerky because it has uses the same amount of time to tween for each of the line segments. some are shorter while others are longer. You could store the previous position and use it with the current position to calculate the distance, and based on that generate a decent for each TweenLite instance. Also feel free to modify that class any way you need(say you want to use a Timer instead, etc.)
Update
我有时间再修补一下.我稍微更改了导出器,现在它还期望目标对象的最大距离.这将是选择的宽度或高度(所有线条),具体取决于哪一个更大(宽度与高度).存储先前的x和y值并用于计算距离,然后将该距离除以行进的最大距离.这又用于缩放每个补间的时间.此外,我已将缓动设置为线性,因为默认(Quad.easeOut)已添加到抖动中.时机不是很准确,但看起来好一点.在这里和这里更新了fla
更新的时间线代码:
import com.codeazur.as3swf.*;
import com.codeazur.as3swf.tags.*;
import com.codeazur.as3swf.exporters.*;
this.loaderInfo.addEventListener(Event.COMPLETE, completeHandler);
function completeHandler(e:Event):void {
var swf:SWF = new SWF(this.loaderInfo.bytes);//new SWF(URLLoader(e.target).data as ByteArray);
var doc:AS3ShapeTweenLiteExporter = new AS3ShapeTweenLiteExporter(swf,"ball",1,300);
// Loop over all tags
for (var i:uint = 0; i < swf.tags.length; i++) {
var tag:ITag = swf.tags[i];
// Check if tag is a DefineShape
if (tag is TagDefineShape) {
// Export shape tween
TagDefineShape(tag).export(doc);
}
}
trace(doc.actionScript);
System.setClipboard(doc.actionScript);
}
Run Code Online (Sandbox Code Playgroud)
在更新的出口:
再次,随时修补.
更新2:
好的,这是另一种方法......
从Illustrator CS4开始,您可以通过文件>保存副本>选择FXG文件类型将图形保存为FXG 这是我使用的fxg文件.
日本再做一次:)惊人的Lib Spark包含一个FXG Parser.还有一个SVGParser,但是现在我只玩了fxg.
所以第一步是下载库:
svn export http://www.libspark.org/svn/as3/FxgParser
Run Code Online (Sandbox Code Playgroud)
您可以使用该示例,因为您使用的是Flash CS5.解析器使用TLF进行文本.我没有费心下载整个flex4 sdk以获得swc和设置.我刚刚注释了Text解析器,因为我们关注路径.注释掉的课程位于底部.
The library contains a Path parser which is cloned and modified to get some animation code: PathTween.as You might recognize some of the variables from the as3swf classes. Here are some explanation for some of the variables I added:
Also, I've done a quickfix, added a default winding, since sometimes, the winding attribute might be missing from the .fxg file and that breaks the parser.
In order to use you need to make a minor change to FxgFactory.as so it uses the PathTween parser instead of the default Path class.
private static const PARSERS:Array = [ Graphic , Group , Library,
Path , Ellipse, Rect, Line,
BitmapGraphic, BitmapImage,
TextGraphic, RichText ];
Run Code Online (Sandbox Code Playgroud)
becomes:
private static const PARSERS:Array = [ Graphic , Group , Library,
PathTweenTracer , Ellipse, Rect, Line,
BitmapGraphic, BitmapImage,
TextGraphic, RichText ];
Run Code Online (Sandbox Code Playgroud)
Finally, some basic timeline code that uses all these:
import fxgparser.*
import fxgparser.parser.*;
var fxgurl:String = "fingerprint.fxg";
var fxgSprite:FxgDisplay;
var loader:URLLoader = new URLLoader( new URLRequest( fxgurl ) );
loader.addEventListener( Event.COMPLETE , displayData );
//some setup
PathTween.MAX_DISTANCE = 360;//change this to fit your shape's largest dimension(width || height)
PathTween.TIME = 2;//change this to your needs
PathTween.TARGET = "ball";//a name of a target clip that will be incremented for each move,line,curve
function displayData( e:Event ):void {
var fxgxml:XML = XML( e.currentTarget.data );
fxgSprite = new FxgDisplay( fxgxml ); //parse SVG
System.setClipboard(PathTween.CODE);
//make some clips for the tester
trace(getClips());
addChild( fxgSprite );
}
function getClips():String {
var result:String = 'this.filters = [new GlowFilter(0x00ff99)]\r';
var clipsNum:int = PathTween.ID;
var target:String = PathTween.TARGET;
for(var i:int = 0 ; i < clipsNum ; i++)
result += 'var '+(target+i)+':Sprite = new Sprite();\r'+(target+i)+'.graphics.beginFill(0x00ff00);\r'+(target+i)+'.graphics.drawCircle(-2,-2,4);\r'+(target+i)+'.graphics.endFill();\raddChild('+(target+i)+');\r';
return result;
}
Run Code Online (Sandbox Code Playgroud)
This is fairly simple:
Then I opened up a fresh fla file and:
You can see the result and get the fla.
So far, as3swf is cool once you've got the fla ready with pasted illustrator paths, could be faster since as3swf works with bytes. What I like about the FXG approach:
This actually got fun, with individual timelines, so I made yet another copy that draws some cheesy trails into a bitmap data.
Here's the PathTweenTracer class, like the previous, place this in the parser package. Again, the PARSERS constant needs to be updated inside FxgFactory:
private static const PARSERS:Array = [ Graphic , Group , Library,
PathTweenTracer , Ellipse, Rect, Line,
BitmapGraphic, BitmapImage,
TextGraphic, RichText ];
Run Code Online (Sandbox Code Playgroud)
The timeline code is pretty much the same. The result looks nice (source)
Here are some screenshots of the generated animation:
Commented out TextGraphic.as
The FXG approach would fit the question better('Using pure actionscript, how can I move a symbol following each of the lines, without using predefined Motion Guides ?')
As for the nested question('Are these drawing objects accessible through AS3 or I should convert them to symbols/whatever format necessary ?' ) :
As @Casey mentioned, you cannot access the graphics once they're set. Using the updated Graphics API you can copy graphics from one Graphics instance into another, but that doesn't expose the commands. I remember Tink had something way before Flash Player 10, but I don't know what's the progress on that.
HTH