项目地址:as3timeline
本意是想做个表现录像回放的时间轴.API按照Flash IDE的JSFL来设计的.所以如果大胆幻想一下,也许可以做出个Flash的Flash动画编辑工具.
本教程讲解窗口(图片)拖动特效的制作.
主要是利用drawTriangles绘制变形位图,用TweenLite实现移动过程的缓动.
先看下最终的效果(鼠标点击拖动面板):
大体的思路是:把图片矩形分段,把矩形的运动分解为各个顶点的运动,结合各个顶点利用drawTriangles绘制变形位图,最后用TweenLite加入缓动效果.

接下来逐步讲解:
如果图片位置是pos,要分的段数是segments,取得分段后的顶点,我们通过buildSegments方法来实现.具体如下:
/**
* 对面板分段, 返回顶点(Point)的二维数组
*/
private function buildSegments(pos : Point) : Array
{
var pts : Array = new Array();
// 分段后平均每段的宽/高
var unitW : Number = this.panel.width / segments;
var unitH : Number = this.panel.height / segments;
// 遍历, 把分段后的顶点存放在pts数组(二维)中.
for (var col : int = 0; col < segments + 1; col++)
{
pts[col] = new Array();
for (var row : int = 0; row < segments + 1; row++)
{
pts[col][row] = new Point(pos.x + col * unitW, pos.y + row * unitH);
}
}
return pts;
}
通过buildSegments方法,取得分段后的顶点,并以二维数组([列,行])的形式保存下来.
drawTriangles是FP 10后Graphics增加的方法.可用来绘制三角形,并进行贴图.它提供三个参数
把面板分段后,循环绘制出每一个网格矩形.每一个矩形有四个顶点(tl,tr,br,bl),切分成两个三角形来绘制:

绘制(render)方法具体如下:
/**
* 绘制面板
*/
public function render() : void
{
var g : Graphics = this.graphics;
g.clear();
var tl : Point, tr : Point, bl : Point, br : Point;
// 使用drawTriangles绘制分段矩形
var vertices : Vector. = new Vector.();
var indices : Vector. = new Vector.();
var indiceIndex : int;
var uvData : Vector. = new Vector.();
var seg : Number = segments;
for (var col : int = 0; col < segments; col++)
{
for (var row : int = 0; row < segments; row++)
{
// 单个矩形的四个顶点
tl = pts[col][row];
tr = pts[col + 1][row];
br = pts[col + 1][row + 1];
bl = pts[col][row + 1];
vertices.push(tl.x, tl.y, tr.x, tr.y, br.x, br.y, bl.x, bl.y);
var nextU : Number = (col != segments - 1) ? (col + 1) / seg : (1 + 1 / this.panel.width);
var nextV : Number = (row != segments - 1) ? (row + 1) / seg : (1 + 1 / this.panel.height);
uvData.push(col / seg, row / seg, nextU, row / seg, nextU, nextV, col / seg, nextV);
indices.push(indiceIndex, indiceIndex + 1, indiceIndex + 3, indiceIndex + 1, indiceIndex + 2, indiceIndex + 3);
indiceIndex += 4;
}
}
g.beginBitmapFill(new IMAGE().bitmapData);
g.drawTriangles(vertices, indices, uvData);
g.endFill();
}
这里有个问题,我在实际书写drawTriangles的uvData并测试最终效果时,发现右边缘与下边缘都是少一个像素的.所以在遍历到边缘(col == segments – 1 || row == segments – 1)时, 把这一个像素转成百分比(1/panel.width, 1/panel.height)加到uv中.
鼠标拖动的实现主要是侦听处理鼠标的三个事件:MOUSE_DOWN,MOUSE_UP,MOUSE_MOVE
/**
* 侦听鼠标交互
*/
private function buildInteractor() : void
{
this.stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseEventHandler);
this.stage.addEventListener(MouseEvent.MOUSE_UP, mouseEventHandler);
}
/**
* 处理鼠标事件,实现拖动
*/
private function mouseEventHandler(event : MouseEvent) : void
{
switch(event.type)
{
case MouseEvent.MOUSE_DOWN:
this.mouseOffset = new Point(this.mouseX - this.posPt.x, this.mouseY - this.posPt.y);
// 开始拖动
this.stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseEventHandler);
break;
case MouseEvent.MOUSE_UP:
// 结束拖动
this.stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseEventHandler);
break;
case MouseEvent.MOUSE_MOVE:
this.move(this.mouseX - this.mouseOffset.x, this.mouseY - this.mouseOffset.y);
break;
default:
}
}
在鼠标移动时,调用move方法传递目标位置,移动面板.看下一步.
面板移动时,我们先把各个顶点的目标位置通过buildSegments计算出来,然后遍历对每个顶点添加缓动.每个顶点的移动时间需要不一样(如果一样的话,最终效果还是整个面板在平移),这里顶点的移动时间根据它与鼠标的距离来计算得出.
/**
* 实现移动动过程缓动
*/
private function move(tx : Number, ty : Number) : void
{
this.endPt = new Point(tx, ty);
// 计算各个分段顶点的目标位置
var endPts : Array = this.buildSegments(this.endPt);
// 创建缓动引擎
this.engine = new TimelineLite({onUpdate:this.render, onComplete:this.onMoveComplete});
// 遍历, 把分段后的顶点存放在pts数组(二维)中.
for (var col : int = 0; col < segments + 1; col++)
{
for (var row : int = 0; row < segments + 1; row++)
{
var end : Point = endPts[col][row];
var time : Number = Math.sqrt((end.x - mouseX) * (end.x - mouseX) + (end.y - mouseY) * (end.y - mouseY)) / 400;
this.engine.insert(new TweenLite(this.pts[col][row], time, {x:end.x, y:end.y}));
}
}
// 播放缓动
this.engine.play();
}
注意代码在TimelineLite.onUpdate时执行render重新绘制面板.
源码打包,包里不含有TweenLite库.
好了,初步完成,还有很多优化的空间,下回继续.

FlashFirebug 3.0已经推出!
新版本重写显示对象树面板,整合了FlashInspector,也修复了大量的bug。
除此之外,FlashFirebug 3.0增加了专业版,专业版多出的功能是控制台(Console),通过控制台你可以运行AS3代码。我想对绝大多数用户来说非专业版的功能已经够用了。
更多信息请访问:http://www.o-minds.com/products/flashfirebug
HtmlText目的是方便对TextField.htmlText字符串进行分割,如下图:

可以直接利用TextField.text来的字符索引来定位分割,但返回的字符串仍保留html的所有标签。使用方法如下:
var html:HtmlText = new HtmlText('Hello <b>world</b>!');
//输出<b>world</b>,而不是<b>wo
trace(html.slice(5, 10));
一个简单的应用:HtmlText实现支持html的打字效果:
关于在位图上像绘制直线的算法,可以参见:http://free.pages.at/easyfilter/bresenham.html。但是不同于在位图上绘制直线,需要的是:一条直线经过哪些格子。






源码:
/**
* 返回网格中两个点,连线经过的格子。
* @see http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
*/
public static function determineTouchedTiles(p0:Point, p1:Point):Vector.
{
var touched:Vector.=new Vector.();
var x0:Number=p0.x;
var y0:Number=p0.y;
var x1:Number=p1.x;
var y1:Number=p1.y;
var steep:Boolean=Math.abs(y1 - y0) > Math.abs(x1 - x0);
if (steep)
{
x0=p0.y;
y0=p0.x;
x1=p1.y;
y1=p1.x;
}
if (x0 > x1)
{
var x0_old:Number=x0;
var y0_old:Number=y0;
x0=x1;
x1=x0_old;
y0=y1;
y1=y0_old;
}
var ratio:Number=Math.abs((y1 - y0) / (x1 - x0));
var mirror:int=y1 > y0 ? 1 : -1;
for (var col:int= Math.floor(x0); col < Math.ceil(x1); col++)
{
var currY:Number=y0 + mirror * ratio * (col - x0);
//第一格不进行延边计算
var skip:Boolean = false;
if(col == Math.floor(x0)){
skip = (int(currY) != int(y0));
}
if(!skip){
if (!steep)
{
touched.push(new Point(col, Math.floor(currY)));
}
else
{
touched.push(new Point(Math.floor(currY), col));
}
}
//根据斜率计算是否有跨格。
if ((mirror > 0 ? (Math.ceil(currY) - currY) : (currY - Math.floor(currY))) < ratio)
{
var crossY:int = Math.floor(currY) + mirror;
//判断是否超出范围
if(crossY>Math.max(int(y0), int(y1)) || crossY
//跨线格子
if (!steep)
{
touched.push(new Point(col, crossY));
}
else
{
touched.push(new Point(crossY, col));
}
}
}
return touched;
}
FlashInspector与FlashFirebug(2.0)和Flash Builder的概要分析工具(Profiler)都会设置mm.cfg的PreloadSWF参数, 所以会产生冲突, 导致Flash Builer的Profiler失效. 如果遇到这种情况, 可以先禁用FlashInspector和FlashFirebug(2.0), 或者为Firefox建个新的Profile.

Flash Inspector更新至0.2.3. 加入了我最期待的一个功能:与FlashFirebug整合. FlashFirebug是对Flash开发很有用的一个调试工具. 但是使用它必须在swf里面先导入FlashFirebug的一些类. 通过Flash Inspector就不必这么麻烦了.
Flash Inspector采用了插件机制, 对FlashFirebug的支持, 其实就是编写一个插件负责与FlashFirebug交互. 要使用这个插件需要Firefox安装:Firebug(对于使用Firefox的前端开发者这应该是必备了吧?), FlashFirebug, Flash Inspector.
安装之后, 在状态栏上右击Flash Inspector的图标, 勾选”FlashFirebug”. 刷新一下页面.
不过FlashFirebug本身是针对自主项目的, 要求swf必须是”allowScriptAccess”的. 所以网页的swf不满足这个条件就没办法使用Flash Inspector的这个功能. Flash Inspector会尝试10次连接Flash Firebug, 如果连接失败, 会在左上角的工具栏中显示一个tip.
这次更新也加了对Firefox 4的支持.
现在访问Flash Inspector的主页,只能看到FlashInspector 0.1.7版本。其它版本不是被删除了,而是因为被禁用而没有列出来。
下面是Flash Inspector的组件管理面板的截图,可以看到很基本上所有版本都被禁用了。

Mozilla(应该是在上周)修改了关于附加组件的策略,Flash Inspector所有未审核过的版本全部被禁用了。Flash Inspector 0.1.7是Mozilla唯一审核过的一个版本。坦白讲这挺挫伤对Flash Inspector开发的积极性,因为Flash Inspector被审核很难通过,而一个不为人知不为人用的东西,做了有虾米意义呢?
关于Firefox大量组件的审核,我非常理解Mozilla,想象得出来他们的工作量非常的大。
Flash Inspector很难通过审核的原因:Flash Inspector包含了三个的swf文件,提交新版本后,最快一周内,开始接受审核,审核人员可以很容易看到JS、文本文件的哪些代码修改、增减,但是只能看三个swf文件发生了改变,为了保证这些文件是安全的,我会收到一封邮件要求提供这三个swf文件的源代码,当然我立马就给发了过去,啥子时候能审核通过真是不知道。

FlashInspector 0.2.2,更新主要包括:
最后,希望FlashInspector对你有用。