By Zevan | March 21, 2009
Actionscript:
-
var t:Number=0, cos:Number, sin:Number;
-
-
var canvas:BitmapData = new BitmapData(400,400,false, 0x000000);
-
addChild(new Bitmap(canvas));
-
-
var shape:Shape = new Shape();
-
with(shape.graphics) beginFill(0x568338, .2), drawCircle(0,0,10);
-
-
addEventListener(Event.ENTER_FRAME, onLoop);
-
function onLoop(evt:Event):void {
-
-
t += .1;
-
// -- low precision sine/cosine
-
//always wrap input angle to -PI..PI
-
if (t <-3.14159265){
-
t += 6.28318531;
-
}else{
-
if (t> 3.14159265)
-
t -= 6.28318531;
-
}
-
-
//compute sine
-
if (t <0){
-
sin = 1.27323954 * t + .405284735 * t * t;
-
}else{
-
sin = 1.27323954 * t - 0.405284735 * t * t;
-
}
-
-
//compute cosine: sin(t + PI/2) = cos(t)
-
t += 1.57079632;
-
if (t> 3.14159265){
-
t -= 6.28318531;
-
}
-
-
if (t <0){
-
cos = 1.27323954 * t + 0.405284735 * t * t
-
}else{
-
cos = 1.27323954 * t - 0.405284735 * t * t;
-
}
-
t -= 1.57079632;
-
-
// move the shape
-
shape.x = 200 + 100 * cos;
-
shape.y = 200 + 100 * sin;
-
-
// draw to the canvas
-
canvas.draw(shape, shape.transform.matrix);
-
}
This snippet draws a circle using low precision sine and cosine... you'll notice that its not a perfect looking circle:
Back in January I saw this blog post by Michael Baczynski over at http://lab.polygonal.de/. The blog post describes a technique for fast sine and cosine approximation - (I highly recommend giving it a read - very fun stuff).
It's worth noting that there is a higher precision sine and cosine that will likely draw a better looking circle but will be about half as fast. According to the original post ... the low precision technique is approximately 14x faster than using Math.cos()/Math.sin().
There some other really great posts over at polygonal go check them out.
Also posted in Math | Tagged actionscrpt, flash |
By Zevan | March 18, 2009
Actionscript:
-
[SWF(width = 400, height = 400)];
-
var canvas:BitmapData = new BitmapData(400,400, false, 0x000000);
-
var eraser:BitmapData = new BitmapData(400,400, true, 0x11000000);
-
addChild(new Bitmap(canvas));
-
-
var particles:Array = new Array();
-
for (var i:int = 0; i <500; i++){
-
particles.push(makeParticle());
-
}
-
-
addEventListener(Event.ENTER_FRAME, onLoop);
-
function onLoop(evt:Event):void {
-
canvas.copyPixels(eraser, eraser.rect, new Point(0,0), null, null, true);
-
for (var i:int = 0; i <particles.length; i++){
-
particles[i]();
-
}
-
}
-
-
function makeParticle():Function {
-
var dx:Number, dy:Number;
-
var x:Number = 200;
-
var y:Number = 200;
-
var vx:Number = Math.random() * 4 - 2;
-
var vy:Number = Math.random() * 4 - 2;
-
var ang:Number;
-
return function():void {
-
x += vx;
-
y += vy;
-
dx = 200 - x;
-
dy= 200 - y;
-
if (Math.sqrt((dx * dx) + (dy * dy))> 130){
-
ang = Math.atan2(dy, dx) / Math.PI * 180;
-
vx = Math.cos(ang);
-
vy = Math.sin(ang);
-
}
-
canvas.setPixel(x, y, 0xFFFFFF);
-
}
-
}
This is an interesting variation on yesterdays post. The result will looks like this...
Click to view swf...
I also decided to do a processing port of this with 3,000 particles:
Processing Version
The processing version eventually evolved into this:
Click for enlarged version...
By Zevan | March 17, 2009
Actionscript:
-
var canvas:BitmapData = new BitmapData(400,400, false, 0xFFFFFF);
-
addChild(new Bitmap(canvas));
-
var eraser:BitmapData = new BitmapData(400,400, true, 0x33FFFFFF);
-
-
var particles:Array = new Array();
-
for (var i:int = 0; i <1000; i++){
-
particles.push(makeParticle());
-
}
-
-
addEventListener(Event.ENTER_FRAME, onLoop);
-
function onLoop(evt:Event):void {
-
canvas.copyPixels(eraser, eraser.rect, new Point(0,0), null, null, true);
-
for (var i:int = 0; i <particles.length; i++){
-
particles[i]();
-
}
-
}
-
-
function makeParticle():Function {
-
var dx:Number, dy:Number;
-
var x:Number = 200;
-
var y:Number = 200;
-
var vx:Number = Math.random() * 4 - 2;
-
var vy:Number = Math.random() * 4 - 2;
-
return function():void {
-
x += vx;
-
y += vy;
-
dx = x - 200;
-
dy= y - 200;
-
if (Math.sqrt((dx * dx) + (dy * dy))> 100){
-
vx *= -1;
-
vy *= -1;
-
}
-
canvas.setPixel(x, y, 0x000000);
-
}
-
}
This creates a circular area filled with moving particles/pixels. It makes use of yesterdays functional programming techniques.
By Zevan | March 16, 2009
Actionscript:
-
var moverNum:int = 40;
-
var movers:Array = new Array();
-
-
for (var i:int = 0; i<moverNum; i++){
-
movers.push(makeMover());
-
}
-
-
addEventListener(Event.ENTER_FRAME, onLoop);
-
function onLoop(evt:Event):void {
-
for (var i:int = 0; i<moverNum; i++){
-
movers[i]();
-
}
-
}
-
-
function makeMover():Function{
-
// mover vars & setup
-
var xVel:Number = Math.random() * 5 + 1;
-
var right:Number = stage.stageWidth + 30;
-
var s:Shape = Shape(addChild(new Shape()));
-
with(s.graphics) beginFill(0xFF0000), drawCircle(0,0,5);
-
s.x = Math.random() * stage.stageWidth;
-
s.y = Math.random() * stage.stageHeight;
-
// return a "run" function
-
return function():void {
-
s.x += xVel;
-
if (s.x> right){
-
s.x = -30;
-
}
-
}
-
}
This snippet creates 40 shapes that move to the right at a random velocity. When they animate off the right hand side of the stage they return from the left.
The makeMover() function has a series of variable definitions related to the x velocity and position of a Shape. The makeMover() function then returns an anonymous function that contains some logic to move the Shape "s". The anonymous function has access to the makeMover() functions temporary variables...
On the main loop we run all of the anonymous functions - animating all the shapes by their random x velocities.
It would be interesting to write the same program using classes and test the for speed differences. My assumption is that anonymous functions are expensive, but it would still be interesting to see...
Also posted in functions | Tagged actionscript, flash |