Monthly Archives: January 2009

Animate Along Bezier Curve

Actionscript:
1. var circle:Shape = Shape(addChild(new Shape));
2. with(circle.graphics) beginFill(0x000000), drawCircle(0,0,5);
3.
4. var bezierPoint:Point = new Point();
5. function bezier(a:Number, x1:Number, y1:Number, x2:Number, y2:Number, x3:Number, y3:Number):void {
6.         var b:Number =1-a;
7.         var pre1:Number=a*a;
8.         var pre2:Number=2*a*b;
9.         var pre3:Number=b*b;
10.         bezierPoint.x = pre1*x1 + pre2*x2  + pre3*x3;
11.         bezierPoint.y = pre1*y1 + pre2*y2 + pre3*y3;
12. }
13.
14. var inc:Number = 0;
15. var theta:Number = 0;
16.
18. function onLoop(evt:Event):void {
19.
20.      graphics.clear();
21.      graphics.lineStyle(0,0xFF0000);
22.      graphics.moveTo(200,200);
23.      graphics.curveTo(mouseX, mouseY, 400, 200);
24.
25.     theta+= .05;
26.     inc = .5 + .5*Math.sin(theta);
27.
28.     bezier(inc, 200, 200, mouseX, mouseY, 400, 200);
29.     circle.x = bezierPoint.x;
30.     circle.y = bezierPoint.y;
31. }

The above animates a circle along a quadratic bezier curve. This snippet was written in response to a question spurned by some of the recent bezier posts. I used Math.sin() to animate the circle but you could just as easily use modulus... simply replace lines 25-26 with the following:

Actionscript:
1. inc += .03;
2. inc %= 1;

Posted in Graphics, bezier, graphics algorithms, motion | Tagged , | 3 Comments

Seamless Tiles

Actionscript:
1. [SWF(width=600, height=500, backgroundColor=0xFFFFFF, frameRate=30)]
2.
3. function seamlessTile(img:BitmapData, featherSize:Number = 5):BitmapData{
4.     var pnt:Point = new Point(0,0);
5.     var tile:BitmapData = new BitmapData(img.width, img.height, true, 0xFF000000);
6.     tile.copyPixels(img, img.rect, pnt, null, null, true);
7.
8.     var flipped:BitmapData = new BitmapData(img.width, img.height, true, 0xFF000000);
9.     var m:Matrix = new Matrix();
10.     m.scale(-1, 1);
11.     m.translate(tile.width,0);
12.     flipped.draw(tile, m);
13.
14.     var aChannel:BitmapData = new BitmapData(img.width, img.height, true, 0x00000000);
15.     var grad:Sprite = new Sprite();
16.     m.createGradientBox(img.width, img.height, 0, 0, 0);
17.
19.
22.
23.     tile.copyPixels(flipped, flipped.rect, pnt, aChannel, pnt, true);
24.
25.     m.identity();
26.     m.scale(1, -1);
27.     m.translate(0,tile.height);
28.     flipped.draw(tile, m)
29.
30.     aChannel.fillRect(aChannel.rect, 0x00000000);
31.     m.createGradientBox(img.width, img.height, Math.PI / 2, 0, 0);
34.
37.
38.     tile.copyPixels(flipped, flipped.rect, pnt, aChannel, pnt, true);
39.     return tile;
40. }
41.
42. // test out the function:
43. var canvas:BitmapData = new BitmapData(600, 470, true, 0xFF000000);
45.
49. var texture:BitmapData;
50.
52.     texture =  Bitmap(image.content).bitmapData;
55. }
56.
57. function onLoop(evt:Event):void{
58.     var tile:BitmapData = seamlessTile(texture, Math.max(1,mouseX/30));
59.     var p:Point = new Point();
60.     for (var i:int = 0; i<8; i++){
61.         p.x = (i % 4) * tile.width;
62.         p.y = int(i / 4) * tile.height;
63.         canvas.copyPixels(tile, tile.rect, p);
64.     }
65. }

The above demos a function called seamlessTile() which takes a BitmapData object and uses an oldschool seamless tile technique on it.

The result is that you can have an image that would normally tile like this:

end up looking like this:

I learned how seamless tiles worked by observing the KPT seamless welder filter while I was in highschool. I wish I could dig up all that old KPT stuff again....

There are better seamless tile algorithms out there.... this one is very primitive, but it will work nicely if used properly. Could work well with a composite texture in Papervision 3D for instance...

| Tagged , | 5 Comments

Glitch Auto-asteroids

Actionscript:
1. [SWF(width=600, height=400, backgroundColor=0x000000, frameRate=30)]
2. // make some ships
3. for (var i:int = 0; i<10; i++) makeShip();
4. //
5. function makeShip():void {
6.     // setup vars
8.     // draw and position the char
9.     with(char.mc) graphics.lineStyle(0,0xFFFFFF), graphics.moveTo(-15, -5), graphics.lineTo(0, 0), graphics.lineTo(-15, 5), x=char.posX, y=char.posY;
10.     // loop
12.         // change position based on velocity, .9 friction
13.         with (char) posX += velX *= .9, posY += velY *= .9;
14.         // randomize radius and theta
15.         if (int(Math.random()*10) == 1) char.thetaDest += Math.random()*2-1;
16.         if (int(Math.random()*90) == 1) char.rad = Math.random()*4 + 4
17.         // apply changes to velocity
18.         char.theta += (char.thetaDest - char.theta) / 12;
19.         char.velX = char.rad * Math.cos(char.theta);
20.         char.velY = char.rad * Math.sin(char.theta);
21.         // screen bounds
22.         if (char.posX> 620) char.posX = -20;
23.         if (char.posX <-20) char.posX = 620;
24.         if (char.posY> 420) char.posY = -20;
25.         if (char.posY <-20) char.posY = 420;
26.         // rotation
27.         char.mc.rotation = (Math.abs(char.mc.y - char.posY)>.7 || Math.abs(char.mc.x - char.posX)> .7) ?  Math.atan2(char.posY - char.mc.y,char.posX -  char.mc.x) / Math.PI * 180 : char.mc.rotation;
28.         // shoot
29.         if(int(Math.random()*100) <20) shootBullet(char, 5 * Math.cos(char.mc.rotation * Math.PI / 180)+ char.velX, 5 * Math.sin(char.mc.rotation * Math.PI / 180) + char.velY);
30.         // apply position
31.         with(char) mc.x = posX, mc.y = posY;
32.         });
33. }
34. //
35. function shootBullet(char:Object, vx:Number, vy:Number):void{
36.     var b:MovieClip = MovieClip(addChild(new MovieClip()));
37.     b.life = 0;
38.     with(b) graphics.beginFill(0xFFFFFF), graphics.drawCircle(0,0,2), x = char.mc.x, y = char.mc.y;
40.             with (b) x += vx, y += vy, life++;
41.             if (b.life> 30) b.removeEventListener(Event.ENTER_FRAME, arguments.callee), removeChild(b);
42.     });
43. }

An asteroids inspired code snippet. See the swf here.

Zeno’s [classic easeOut]

Actionscript:
1. stage.frameRate = 30;
2. var circle:Shape = Shape(addChild(new Shape()));
3. with(circle.graphics) beginFill(0x000000), drawCircle(0,0,10);
4. circle.y = 50;
5.