Tree
Original (java): http://www.hyuki.com/math/
AS3 ported by flashrod
// Original (java): http://www.hyuki.com/math/
// AS3 ported by flashrod
package {
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
[SWF(width="465", height="465", backgroundColor="0xFFFFFF", frameRate="30")]
public class Tree extends Sprite {
private static const LEVEL:Number = 12.0;
private var t:Turtle;
public function Tree() {
var bd:BitmapData = new BitmapData(465, 465);
addChild(new Bitmap(bd));
var queue:Array = [];
t = new Turtle(new AnimatedCanvas(new BitmapCanvas(bd), queue));
t.setxy(465 * .5, 465 * .8);
t.pendown();
drawtree(LEVEL);
addEventListener(Event.ENTER_FRAME, function(ev:Event):void {
for (var i:int = 0; i < 10; ++i) {
if (queue.length > 0) {
queue.shift()();
}
}
});
}
private function drawtree(n:Number):void {
if (n > 0) {
var level:Number = (LEVEL - n) / LEVEL;
var len:Number = n * 3.6;
t.left(18);
t.pendown();
t.setcolor(gray(level), 1-level);
t.forward(len);
drawtree(n - 1);
t.penup();
t.back(len);
t.right(18);
t.right(18);
t.pendown();
t.setcolor(gray(level), 1-level);
t.forward(len);
drawtree(n - 1);
t.penup();
t.back(len);
t.left(18);
}
}
private static function gray(n:Number):uint {
var a:int = n * 255;
return (a << 16) + (a << 8) + a;
}
}
}
class Turtle {
private var canvas:Canvas;
private var down:Boolean = false;
private var angle:Number = 0.0;
private var posx:Number = 0.0;
private var posy:Number = 0.0;
private var color:uint = 0x000000;
private var alpha:Number = 1.0;
public function Turtle(canvas:Canvas) { this.canvas = canvas; }
public function setcolor(color:uint, alpha:Number=1.0):void {
this.color = color;
this.alpha = alpha;
}
public function pendown():void { down = true; }
public function penup():void { down = false; }
public function setxy(x:Number, y:Number):void {
if (down) {
canvas.line(posx, posy, x, y, color, alpha);
}
this.posx = x;
this.posy = y;
}
public function forward(length:Number):void {
setxy(posx + length * Math.sin(angle), posy - length * Math.cos(angle));
}
public function back(length:Number):void { forward(-length); }
public function right(a:Number):void { angle += a * Math.PI / 180; }
public function left(a:Number):void { right(-a); }
}
interface Canvas {
function line(x0:int, y0:int, x1:int, y1:int, c:uint, a:Number):void;
}
class AnimatedCanvas implements Canvas {
private var canvas:Canvas;
private var queue:Array;
public function AnimatedCanvas(canvas:Canvas, queue:Array) {
this.canvas = canvas;
this.queue = queue;
}
public function line(x0:int, y0:int, x1:int, y1:int, c:uint, a:Number):void {
queue.push(function():void { canvas.line(x0, y0, x1, y1, c, a); });
}
}
import flash.display.BitmapData;
class BitmapCanvas implements Canvas {
private var bd:BitmapData;
public function BitmapCanvas(bd:BitmapData) { this.bd = bd; }
/** Bresenham's line algorithm
* @param x0 x0
* @param x0 y0
* @param x1 x1
* @param y1 y1
* @param c color
* @param a alpha value
*/
public function line(x0:int, y0:int, x1:int, y1:int, c:uint, a:Number):void {
var steep:Boolean = Math.abs(y1 - y0) > Math.abs(x1 - x0);
var t:int;
if (steep) {
t=x0; x0=y0; y0=t;
t=x1; x1=y1; y1=t;
}
if (x0 > x1) {
t=x0; x0=x1; x1=t;
t=y0; y0=y1; y1=t;
}
var deltax:int = x1 - x0;
var deltay:int = Math.abs(y1 - y0);
var error:int = 0;
var ystep:int = (y0 < y1) ? 1 : -1;
var y:int = y0;
for (var x:int = x0; x <= x1; ++x) {
if (steep) {
plot(y,x, c, a);
} else {
plot(x,y, c, a);
}
error += deltay;
if (2*error >= deltax) {
y += ystep;
error -= deltax;
}
}
}
public function plot(x:int, y:int, c:uint, a:Number):void {
bd.setPixel(x, y, blend(bd.getPixel(x, y), c, a));
}
private static function blend(d:uint, s:uint, a:Number):uint {
var rd:int = (d >> 16) & 0xFF;
var gd:int = (d >> 8) & 0xFF;
var bd:int = d & 0xFF;
var rs:int = (s >> 16) & 0xFF;
var gs:int = (s >> 8) & 0xFF;
var bs:int = s & 0xFF;
var e:Number = 1 - a;
var r:int = rd * e + rs * a;
var g:int = gd * e + gs * a;
var b:int = bd * e + bs * a;
return (r << 16) | (g << 8) | b;
}
}