我已经将Adobe Illustrator文档中的许多路径直接导入到Flash文件中。路径在场景中作为“图形对象”存在。使用纯动作脚本,如何在不使用预定义的运动指南的情况下沿每行移动符号。
编辑:我已经附加了Flash文件,其中充满了图形对象。
http://rapidshare.com/files/406497264/pather.fla.html
问题是:这些图形对象是否可以通过AS3访问,还是应该将它们转换为符号/任何必要的格式?并请举一些AS示例。
谢谢!
最佳答案
好问题+1
我见过Fla在工作,没有CS5在家,但我了解您要达到的目标。
我的方法是:
从Flash CS4开始,您可以复制路径并将其粘贴到Motion Tween中。这将与“经典补间”的“运动指南”功能相似。这有很多问题:
目标是动画,您无法对其进行动作控制。您可以设置一个计时器
在AnimationFactory动作期间,但变得麻烦。
显然,这是一个禁忌。
我偶然发现了这个非常方便的jsfl script by ericlin,它遍历了舞台上选择的所有形状。如果选择路径并运行脚本(可以双击jsfl文件),则将获得解析的坐标。
我使用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]);
}
}
*注意:*此处的ptArray未显示,因为这会浪费太多空间。
result并不是很好。您可以看看fla来了解我的意思。
jsfl脚本可以更改,但是我看到您强调了动作脚本的用法,所以这也不是不行。
Claus Wahlers开发了一个惊人的as3库as3swf,它允许Flash / Flex开发人员在运行时反编译swfs。这是awesome article的解释
swfs内部形状的来龙去脉。已经写了很多exporters。
我只是复制了AS3ShapeExporter并将as3绘制命令更改为TweenLite代码。基本上,我将moveTo替换为快速补间,以将lineTo替换为常规补间,将curveTo替换为bezier补间。 Tween Lite的BezierPlugin幸运地使用了二次贝塞尔曲线,就像curveTo一样。
这是您需要粘贴到包含形状的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",.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);
}
基本上,我会加载swf,一旦准备就绪,便将其字节传递给as3swf,然后使用AS3ShapeTweenLiteExporter解析形状标签并吐出动作脚本。
我传递给构造函数的3个参数是:swf实例,补间目标的名称和每个补间的时间。
这是我被黑在一起的课程的样子:
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);
}
}
}
下载as3swf之后,您需要将此类保存在导出程序包中。
这是result。您可以下载其fla,也可以下载生成该代码的fla。
这是一个纯ActionScript版本,效果不错。
动画看起来很生涩,因为它为每个线段使用了相同的时间进行补间。有些较短,而另一些较长。您可以存储先前的位置,并将其与当前位置一起使用以计算距离,并基于此为每个TweenLite实例生成一个体面的图像。
也可以根据需要随意修改该类(例如您想使用Timer等等)。
更新
我有时间再修改一点。
我稍微更改了导出器,现在它也期望目标对象可以移动最大距离。这将是所选内容的宽度或高度(所有行),具体取决于哪一个较大(宽度与高度)。先前的x和y值被存储
并用于计算距离,然后将该距离除以行进的最大距离。依次使用它来缩放每个补间上的时间。另外,我将缓动设置为线性,因为默认值(Quad.easeOut)已添加到抖动中。计时不是很准确,但是看起来是a bit better。更新了fla的here和here
更新的时间轴代码:
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);
}
updated exporter:
同样,请随意修改。
更新2:
好的,这是另一种方法...
从Illustrator CS4开始,您可以通过文件>保存副本>选择FXG文件类型将图形另存为FXG。
这是我使用的fxg file。
日本再做一次:)
惊人的Lib Spark包含FXG Parser。还有一个SVGParser,但目前我只玩过fxg。
因此,第一步是下载该库:
svn export http://www.libspark.org/svn/as3/FxgParser
由于使用Flash CS5,因此使用示例可能会很好。解析器将TLF用于文本。我没有费心下载整个flex4 sdk来获取swc和设置。我只是注释掉了文本解析器,因为我们关心路径。注释掉的类在底部。
该库包含一个Path解析器,可对其进行克隆和修改以获取一些动画代码:PathTween.as
您可能会认识到as3swf类中的某些变量。
这是我添加的一些变量的一些说明:
另外,我完成了一个快速修复,添加了默认绕线,因为有时,.fxg文件中可能缺少绕线属性,这会破坏解析器。
为了使用它,您需要对 FxgFactory.as 进行较小的更改,以便它使用PathTween解析器而不是默认的Path类。
private static const PARSERS:Array = [ Graphic , Group , Library,
Path , Ellipse, Rect, Line,
BitmapGraphic, BitmapImage,
TextGraphic, RichText ];
变成:
private static const PARSERS:Array = [ Graphic , Group , Library,
PathTweenTracer , Ellipse, Rect, Line,
BitmapGraphic, BitmapImage,
TextGraphic, RichText ];
最后,一些使用所有这些的基本时间轴代码:
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;
}
这很简单:
然后,我打开了一个新的fla文件,并:
您可以看到result并获取fla。
到目前为止,一旦您准备好带有粘贴的插图画家路径的fla,as3swf就会很酷,
可能更快,因为as3swf使用字节。
我喜欢FXG方法:
图形成fla,您只需保存一个
复制为FXG。你可以用一个fla来
生成您需要的所有代码
将路径更改为您的fxg文件
想要动画。
和其他曲线分成lineTo命令,使动画稍微平整。
这实际上很有趣,而且有各自的时间表,所以我又制作了一个副本,画了一些
俗气的痕迹进入位图数据。
Here的PathTweenTracer类与之前的类一样,将其放在解析器包中。
同样,需要在FxgFactory中更新 PARSERS 常量:
private static const PARSERS:Array = [ Graphic , Group , Library,
PathTweenTracer , Ellipse, Rect, Line,
BitmapGraphic, BitmapImage,
TextGraphic, RichText ];
timeline代码几乎相同。
result看起来不错(source)
以下是生成的动画的一些屏幕截图:
注释掉TextGraphic.as
FXG方法将更适合该问题(“使用纯动作脚本,如何在不使用预定义的运动向导的情况下沿每行移动符号?”)
至于嵌套的问题(“这些图形对象是否可以通过AS3访问,或者我应该将它们转换为符号/任何必要的格式?”):
正如@Casey所提到的,设置完图形后就无法访问它们。使用更新的Graphics API,您可以将图形从一个Graphics实例复制到另一个Graphics实例,但这不会公开命令。我记得Tink在Flash Player 10之前就有了something,但是我不知道它的进展如何。
高温超导
关于flash - 在图形对象周围移动符号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3170824/