woderfl 社区里面有着很多as3的制作技巧,其中有一本书里面介绍着很多相关的解说。里面大部分好的代码都是来自wonderfl里面的人通过自己业余时间编写出来的。这本书目前发现只有亚马逊才有得购买,而且国内只有外购才能买到日文版本。所以没办法看到里面的介绍和解说。不过好运的事,里面解说的代码在beautifl网站都有收录进去,所以很方便进行对里面代码阅读。因为这本书据说只是解说偏多,理论的东西不是很多。相比kp的书,这个偏案例。不过之所以有意思的是,这本书里面的代码技巧性比较强,收录的代码都是在as3方面有很深功底和创意的人。这本书编写作者是一个对as3有丰富经验的人名字叫池田泰延(ClockMaker),当中还有一些关于他的精彩实验。我们都可以在他的博客里面看到。
这本书的目录可以上亚马逊进行阅读,第一章节里面解说是采用HelloWorld开头进行解说。
案例一可以参考这里:http://wonderfl.net/c/nCFQ
案例中采用的技巧如下:(采用两层循环遍历位图数据,获取颜色值,并根据坐标信息产生运动效应)
过程:
创建一个文本,通过一个位图进行复制。
获取到位图对其进行遍历,获取不同的颜色。然后采用Tweener的类库对其产生不规则的运动。
本次使用的位图API 不多,获取颜色是采用getPixel 这个函数,整体看起来这个案例并不复杂,但是里面采用的技巧也是很普遍的一种手法。
如 随机位置,扫描像素值,延迟时间产生运动过程,这些手法也是在as3里面常用到。在这本书里面收录很多案例。
package{ import flash.display.*; import flash.text.*; import flash.filters.*; import flash.geom.*; import caurina.transitions.Tweener; public class Foo extends Sprite{ private var bd:BitmapData; public function Foo():void{ var tf:TextField = new TextField(); tf.textColor = 0x000000; tf.text = "Hello\nWorld!!!"; tf.autoSize = "left"; bd = new BitmapData(tf.width, tf.height, false, 0x3399ff); bd.draw(tf); bd.applyFilter(bd, bd.rect, new Point(), new BlurFilter()); bd.draw(tf); for(var i:int = 0; i < bd.width; i++){ for(var j:int = 0; j < bd.height; j++){ Tweener.addTween( randomize(addChild(new Circle(bd.getPixel(i, j)))), { x: i * 10, y: j * 10, alpha: 1, delay: (i + j) * .2 * Math.random(), time: 1 } ); } } } private function randomize(d:DisplayObject):DisplayObject{ d.x = 400 * Math.random(); d.y = 300 * Math.random(); d.alpha = 0; return d; } } } import flash.display.Sprite; class Circle extends Sprite{ public function Circle(color:uint):void{ graphics.beginFill(color); graphics.drawCircle(0, 0, 6); graphics.endFill(); } }
你可以改成其他文本,进行复制,产生的效果也会不一样。
第二案例,收录一个牛人(Saqoosha)制作飘雪字的技巧。效果看起来很漂亮
收录的地址在这里: http://wonderfl.net/c/g9s1
代码收录如下
当中采用了一个闪星的制作技巧,用法很特别。当中也比较核心的一点是采用粒子运动的方式来进行。让整个程序看起来就像一个艺术品那样子。整本书的目录里面可以看到,这些程序都是比较有技巧性而且想法比较独特。看这些代码也是一种享受。
package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.BlendMode; import flash.display.PixelSnapping; import flash.display.Sprite; import flash.events.Event; import flash.filters.BlurFilter; import flash.geom.Matrix; import flash.geom.Point; import flash.text.TextField; import flash.text.TextFieldAutoSize; import flash.text.TextFormat; import net.hires.debug.Stats; [SWF(width=465, height=465, backgroundColor=0x0, frameRate=120)] public class Saq001 extends Sprite { private static const GRAVITY:Number = 20; private static const DRAG:Number = 0.3; private var _canvas:BitmapData; private var _glow:BitmapData; private var _glowMtx:Matrix; private var _forceMap:BitmapData; private var _snow:Array; public function Saq001() { this._canvas = new BitmapData(465, 465, false, 0x0); // カンバスをつくる。ここに 1 pixel ずつ描いていくよ this.addChild(new Bitmap(this._canvas)) as Bitmap; // stage に配置 this._glow = new BitmapData(465 / 4, 465 / 4, false, 0x0); // キラキラを描く用のん。カンバスの 4 分の 1 のサイズ var bm:Bitmap = this.addChild(new Bitmap(this._glow, PixelSnapping.NEVER, true)) as Bitmap; // smoothing を true にして配置 bm.scaleX = bm.scaleY = 4; // 4 倍にする。 bm.blendMode = BlendMode.ADD; // 加算モードで合成 this._glowMtx = new Matrix(0.25, 0, 0, 0.25); // 雪を積もらせるかたちを BitmapData に描く。 var tf:TextField = new TextField(); tf.defaultTextFormat = new TextFormat('Verdana', 64, 0xffffff, true); tf.autoSize = TextFieldAutoSize.LEFT; tf.text = 'Wonderfl!!'; tf.x = (465 - tf.width) / 2; tf.y = (465 - tf.height) / 2; this._forceMap = new BitmapData(465, 465, false, 0x0); this._forceMap.draw(tf, tf.transform.matrix); this._forceMap.applyFilter(this._forceMap, this._forceMap.rect, new Point(0, 0), new BlurFilter(8, 8)); this._snow = []; // 雪パーティクルはここにいれておくよ。 this.addChild(new Stats()); this.addEventListener(Event.ENTER_FRAME, this.update); // 毎フレーム update を呼ぶよ } // 雪を 1 粒発生させる関数 public function emitParticle(ex:Number, ey:Number, s:Number = 1, c:int = 0xffffff, vx:Number = 0, vy:Number = 0):void { var p:SnowParticle = new SnowParticle(); // 作って // パラメータ設定して p.x = ex; p.y = ey; p.vx = vx; p.vy = vy; p.s = s; p.c = c; this._snow.push(p); // 保存 } // 雪を動かすよーー public function update(e:Event):void { this._canvas.lock(); // いっぱい setPixel するときは必ず lock しよう this._canvas.fillRect(this._canvas.rect, 0x0); // カンバスをクリア var n:int = this._snow.length; var d:Number; var gravity:Number = GRAVITY / 1000; // あらかじめ計算しとく while (n--) { var p:SnowParticle = this._snow[n]; p.vy += gravity * p.s; // まず重力を加える p.vx *= 0.99; // 空気抵抗 p.vy *= 0.99; // y 方向にも d = 1 - (this._forceMap.getPixel(p.x, p.y) / 0xffffff) * DRAG; // forceMap にもとづいて抵抗値を計算。黒→速い、白→遅い。 p.vx *= d; // forceMap から得た抵抗値を適用 p.vy *= d; // y 方向にも p.x += p.vx; // 動かす p.y += p.vy; this._canvas.setPixel(p.x, p.y, p.c); // 雪 1 粒描く if (p.y > this.stage.stageHeight) { // もし画面外にでちゃったら this._snow.splice(n, 1); // とりのぞく } } this._canvas.unlock(); // lock したやつは必ず unlock this._glow.draw(this._canvas, this._glowMtx); // キラキラを描く // 雪を発生させますよ n = 10; while (n--) { this.emitParticle(Math.random() * this.stage.stageWidth, 0, Math.random() + 0.5); } } } } class SnowParticle { public var x:Number; public var y:Number; public var vx:Number; public var vy:Number; public var s:Number; public var c:int; public function SnowParticle() { this.x = 0; this.y = 0; this.vx = 0; this.vy = 0; this.s = 1; this.c = 0xffffff; } }
案例三:forked from: RainyDay
链接代码:http://wonderfl.net/c/mkJ9
一个非常酷as3的下雨效果,收录了Saqoosha forked的一个的代码片段。
package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.BlendMode; import flash.display.PixelSnapping; import flash.display.Sprite; import flash.events.Event; import flash.filters.BlurFilter; import flash.filters.ColorMatrixFilter; import flash.geom.Matrix; import flash.geom.Point; import flash.text.TextField; import flash.text.TextFieldAutoSize; import flash.text.TextFormat; import flash.utils.Dictionary; import net.hires.debug.Stats; import frocessing.color.ColorHSV; [SWF(width=465, height=465, backgroundColor=0x0, frameRate=120)] public class RainyDay extends Sprite { private static const GRAVITY:Number = 20; private static const DRAG:Number = 0.7; private static const ZERO_POINT:Point = new Point(0, 0); private var _canvas:BitmapData; private var _glow:BitmapData; private var _glowMtx:Matrix; private var _forceMap:BitmapData; // private var _snow:Array; private var _snow:Dictionary; private var _color:ColorMatrixFilter = new ColorMatrixFilter([ 1, 0, 0, 0, -5, 0, 1, 0, 0, -5, 0, 0, 1, 0, -5, 0, 0, 0, 1, 0 ]); private var _hsv:ColorHSV = new ColorHSV(); private var _blur:BlurFilter = new BlurFilter(1.5, 1.5, 1); public function RainyDay() { this._canvas = new BitmapData(465, 465, false, 0x0); // カンバスをつくる。ここに 1 pixel ずつ描いていくよ this.addChild(new Bitmap(this._canvas)) as Bitmap; // stage に配置 /*this._glow = new BitmapData(465 / 4, 465 / 4, false, 0x0); // キラキラを描く用のん。カンバスの 4 分の 1 のサイズ var bm:Bitmap = this.addChild(new Bitmap(this._glow, PixelSnapping.NEVER, true)) as Bitmap; // smoothing を true にして配置 //bm.scaleX = bm.scaleY = 4; // 4 倍にする。 bm.blendMode = BlendMode.ADD; // 加算モードで合成 this._glowMtx = new Matrix(0.25, 0, 0, 0.25);*/ // 雪を積もらせるかたちを BitmapData に描く。 var tf:TextField = new TextField(); tf.defaultTextFormat = new TextFormat('Verdana', 64, 0xffffff, true); tf.autoSize = TextFieldAutoSize.LEFT; tf.text = 'Rainyday'; tf.x = (465 - tf.width) / 2; tf.y = (465 - tf.height) / 2; this._forceMap = new BitmapData(465, 465, false, 0x0); this._forceMap.draw(tf, tf.transform.matrix); this._forceMap.applyFilter(this._forceMap, this._forceMap.rect, new Point(0, 0), new BlurFilter(8, 8)); // this._snow = []; // 雪パーティクルはここにいれておくよ。 this._snow = new Dictionary(); this.addChild(new Stats()); this.addEventListener(Event.ENTER_FRAME, this.update); // 毎フレーム update を呼ぶよ } // 雪を 1 粒発生させる関数 public function emitParticle(ex:Number, ey:Number, s:Number = 1, c:int = 0x00bfff, vx:Number = 0, vy:Number = 0):SnowParticle { var p:SnowParticle = new SnowParticle(); // 作って // パラメータ設定して p.x = ex; p.y = ey; p.vx = vx; p.vy = vy; p.s = s; p.c = c; // this._snow.push(p); // 保存 this._snow[p] = true; return p; } // 雪を動かすよーー public function update(e:Event):void { this._canvas.lock(); // いっぱい setPixel するときは必ず lock しよう this._canvas.applyFilter(this._canvas, this._canvas.rect, ZERO_POINT, this._color); this._canvas.applyFilter(this._canvas, this._canvas.rect, ZERO_POINT, this._blur); // this._canvas.fillRect(this._canvas.rect, 0x0); // カンバスをクリア // var n:int = this._snow.length; var d:Number; var gravity:Number = GRAVITY / 100; // あらかじめ計算しとく // while (n--) { for (var key:* in this._snow) { var p:SnowParticle = SnowParticle(key); // var p:SnowParticle = this._snow[n]; // p.vx += 0.02; p.vy += gravity * p.s; // まず重力を加える p.vx *= 0.99; // 空気抵抗 p.vy *= 0.99; // y 方向にも d = 1 - (this._forceMap.getPixel(p.x, p.y) / 0xffffff) * DRAG; // forceMap にもとづいて抵抗値を計算。黒→速い、白→遅い。 p.vx *= d; // forceMap から得た抵抗値を適用 var vy:Number = p.vy; p.vy *= d; // y 方向にも if ((vy - p.vy) > 1 && Math.random() < 0.3) { //p.vy = -2; //p.vx = (Math.random() - 0.5) * 3; this.emitParticle(p.x, p.y - 2, 1, p.c, (Math.random() - 0.5) * 6, -(Math.random() * 2 + 1)); this.emitParticle(p.x, p.y - 2, 1, p.c, (Math.random() - 0.5) * 6, -(Math.random() * 2 + 1)); this.emitParticle(p.x, p.y - 2, 1, p.c, (Math.random() - 0.5) * 6, -(Math.random() * 2 + 1)); } var px:int = p.x; var py:int = p.y; p.x += p.vx; // 動かす p.y += p.vy; // this._canvas.setPixel(p.x, p.y, p.c); // 雪 1 粒描く _drawLine(p.x, p.y, px, py, p.c, 1); if (p.y > this.stage.stageHeight) { // もし画面外にでちゃったら // this._snow.splice(n, 1); // とりのぞく delete this._snow[p]; } } this._canvas.unlock(); // lock したやつは必ず unlock //this._glow.draw(this._canvas, this._glowMtx); // キラキラを描く // 雪を発生させますよ // var n = 10; // while (n--) { for (var i:int = 0; i < 4; i++) { _hsv.h = Math.random() * 20 + 180; this.emitParticle(Math.random() * this.stage.stageWidth, -20, Math.random() + 0.5, _hsv.value); } } private function _drawLine(x0:int, y0:int, x1:int, y1:int, color:int, alpha:Number):void { var steep:Boolean = Math.abs(y1 - y0) > Math.abs(x1 - x0); var tmp:int; if (steep) { tmp = x0; x0 = y0; y0 = tmp; tmp = x1; x1 = y1; y1 = tmp; } if (x0 > x1) { tmp = x0; x0 = x1; x1 = tmp; tmp = y0; y0 = y1; y1 = tmp; } var deltax:int = x1 - x0; var deltay:int = Math.abs(y1 - y0); var error:int = deltax / 2; var ystep:int; var y:int = y0; if (y0 < y1) { ystep = 1; } else { ystep = -1; } for (var x:int = x0; x <= x1; x++) { if (steep) { this._canvas.setPixel32(y, x, color | ((alpha * 0xff) << 24)); } else { this._canvas.setPixel32(x, y, color | ((alpha * 0xff) << 24)); } error = error - deltay; if (error < 0) { y = y + ystep; error = error + deltax; } } } } } class SnowParticle { public var x:Number; public var y:Number; public var vx:Number; public var vy:Number; public var s:Number; public var c:int; public function SnowParticle() { this.x = 0; this.y = 0; this.vx = 0; this.vy = 0; this.s = 1; this.c = 0xffffff; } }