Monthly Archives: January 2009

Not a Snippet (wandering robots)

Actionscript:
  1. package {
  2.     import flash.display.Sprite;
  3.    
  4.     [SWF(width=500, height=500, backgroundColor=0xEFEFEF, frameRate=30)]
  5.     public class Main extends Sprite{
  6.         private var _robotManager:RobotManager;
  7.         public function Main(){
  8.           _robotManager = new RobotManager(this, 12);
  9.         }
  10.     }
  11. }
  12.  
  13. class RobotManager{
  14.    
  15.     private var _robots:Array;
  16.     private var _top:Sprite;
  17.     private var _robotNum:int;
  18.    
  19.     public function RobotManager(top:Sprite, robotNum:int){
  20.         _top = top;
  21.         _robotNum = robotNum;
  22.         _robots = new Array();
  23.         setupRobots();
  24.         top.addEventListener(Event.ENTER_FRAME, onRun);
  25.     }
  26.    
  27.     private function setupRobots():void{
  28.         for (var i:int = 0; i<_robotNum; i++){
  29.             _robots[i] = new Robot();
  30.             _robots[i].x = 100+(i % 3) * 150;
  31.             _robots[i].y = 100+int(i / 3) * 100;
  32.             _robots[i].addEventListener("death", onRobotDie);
  33.             _top.addChild(_robots[i]);
  34.         }
  35.     }
  36.     private function onRobotDie(evt:Event):void{
  37.         for (var i:int = 0; i<_robotNum; i++){
  38.             if (_robots[i] == evt.currentTarget){
  39.                 _robots.splice(i, 1);
  40.             }
  41.         }
  42.         _robotNum--;
  43.     }
  44.    
  45.     private function onRun(evt:Event):void{
  46.         collisions();
  47.     }
  48.    
  49.     private function collisions():void{
  50.         var currBot:Robot;
  51.         for (var i:int = 0; i<_robotNum; i++){
  52.             currBot = _robots[i];
  53.             for (var j:int = 0; j<_robotNum; j++){
  54.                 if (currBot != _robots[j]){
  55.                     var dx:Number = currBot.x - _robots[j].x;
  56.                     var dy:Number = currBot.y - _robots[j].y;
  57.                     if (Math.sqrt((dx * dx) + (dy * dy)) <40){
  58.                         currBot.die();
  59.                     }
  60.                 }
  61.             }
  62.         }
  63.     }
  64. }
  65.  
  66. import flash.display.*
  67. import flash.events.*;
  68.  
  69. class Robot extends Sprite{
  70.     private var _inc:Number
  71.     private var _td:Number;
  72.     private var _theta:Number;
  73.     private var _rad:Number;
  74.    
  75.     public function Robot(){
  76.         _theta = Math.random() * (Math.PI * 2);
  77.         _td = _theta;
  78.         _inc = Math.random() * .2 + .05;
  79.         _rad = _inc * 10;
  80.         with(graphics){
  81.             beginFill(0x666666);
  82.             drawRect(-10,-10,20,20);
  83.             endFill();
  84.             beginFill(0x333333);
  85.             drawRect(-5, -5, 20, 10);
  86.             lineStyle(0,0xAAAAAA);
  87.             endFill();
  88.             drawCircle(0,0,20);
  89.         }
  90.         addEventListener(Event.ENTER_FRAME, onRun);
  91.     }
  92.    
  93.     private function onRun(evt:Event):void{
  94.         _td  += _inc;
  95.         _theta += _inc * Math.cos(_td);
  96.         if (x <0 || y <0 || x> 500 || y> 500){
  97.             _theta += Math.PI;
  98.         }
  99.         x += _rad * Math.cos(_theta);
  100.         y += _rad * Math.sin(_theta);
  101.         rotation = _theta / Math.PI * 180;
  102.     }
  103.    
  104.     public function die():void{
  105.         removeEventListener(Event.ENTER_FRAME, onRun);
  106.         addEventListener(Event.ENTER_FRAME, onDie);
  107.     }
  108.    
  109.     private function onDie(evt:Event):void{
  110.         scaleX = scaleY += .1;
  111.         alpha -= .1;
  112.         if (scaleX> 2){
  113.             removeEventListener(Event.ENTER_FRAME, onDie);
  114.             if (parent){
  115.                 parent.removeChild(this);
  116.                 dispatchEvent(new Event("death"));
  117.             }
  118.         }
  119.     }
  120. }

This code should be placed in a document class... not the timeline (hopefully you already know that)

The above creates 12 wandering robots that die when they collide with one another.

This is not a snippet really... but it's only slightly over 100 lines and it contains a few tricks I find myself using from time to time.

You can view the swf here.

Posted in Events, OOP, arrays, motion | Tagged , , | 3 Comments

Canonical Representation of XOR

Actionscript:
  1. // xor
  2. trace(0 ^ 0);
  3. trace(0 ^ 1);
  4. trace(1 ^ 0);
  5. trace(1 ^ 1);
  6.  
  7. trace("canonical representation of xor");
  8. trace(xor(0, 0));
  9. trace(xor(0, 1));
  10. trace(xor(1, 0));
  11. trace(xor(1, 1));
  12.  
  13. function xor(a:int, b:int):int{
  14.     //1-a   is the same as   int(!a)
  15.     return 1-a & b | a & 1-b;
  16. }
  17.  
  18. /*
  19. outputs:
  20. 0
  21. 1
  22. 1
  23. 0
  24. canonical representation of xor
  25. 0
  26. 1
  27. 1
  28. 0
  29. */

I learned about this from reading The Elements of Computing Systems: Building a Modern Computer from First Principles By Noam Nisan and Shimon Schocken

Check out chapter 1 from the above link for an easy to understand description of the canonical representation of a boolean function.

Just a side note... this happens to be the 100th post on actionsnippet.com

Posted in Operators, one-liners | Tagged , | 2 Comments

NAND

Actionscript:
  1. var a:int, b:int;
  2.  
  3. a = 0;
  4. b = 0;
  5.  
  6. trace(int(!(a & b)));
  7.  
  8. a = 0;
  9. b = 1;
  10.  
  11. trace(int(!(a & b)));
  12.  
  13. a = 1;
  14. b = 0;
  15.  
  16. trace(int(!(a & b)));
  17.  
  18. a = 1;
  19. b = 1;
  20.  
  21. trace(int(!(a & b)));
  22.  
  23. /*
  24. outputs:
  25. 1
  26. 1
  27. 1
  28. 0
  29. */
  30.  
  31. /*
  32. NAND
  33. 00    1
  34. 01    1
  35. 10    1
  36. 11    0
  37. */

I started reading "The Elements of Computing Systems: Building a Modern Computer from First Principles" By Noam Nisan and Shimon Schocken. So far it's a very fun read. They talk about the power of NAND in the first chapter....

Posted in Operators, misc | Tagged , | Leave a comment

Variable Swap

Actionscript:
  1. //
  2. // swap some variables
  3. // all techniques except the first are from http://cpptruths.blogspot.com/2006/04/swapping-two-integers-in-one-liner.html
  4. //
  5. var a:Number = 1.1;
  6. var b:Number= 2.2;
  7.  
  8. trace(a, b);
  9.  
  10. // best, fastest, easiest to read way
  11. var t:Number= a;
  12. a = b;
  13. b = t;
  14.  
  15. trace(a, b);
  16.  
  17. // not recommended slower ways:
  18.  
  19. b=a+b-(a=b);
  20.  
  21. trace(a, b);
  22.  
  23. // xor versions will only work with ints and uints
  24. trace("\nxor kills decimals:");
  25.  
  26. // easy to understand xor version
  27. a^=b;
  28. b^=a;
  29. a^=b;
  30.  
  31. trace(a, b);
  32.  
  33. // one line xor version
  34.  
  35. a=(b=(a=b^a)^b)^a;
  36.  
  37. trace(a, b);
  38.  
  39. /* outputs:
  40. 1.1 2.2
  41. 2.2 1.1
  42. 1.1 2.2
  43.  
  44. xor kills decimals:
  45. 2 1
  46. 1 2
  47. */

The above swaps variables a and b in a few different ways. The first way (using a temp variable) is the best and fastest way... the rest of the ways are just interesting and fun.

I was coding and something reminded me that there are obscure variable swapping techniques out there... so I figured I'd google for a bit.... there are tons of examples of these online - with lots of good explanations.... I got the above from this link.

Posted in Operators, one-liners, variables | Tagged , | Leave a comment

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.  
  17. addEventListener(Event.ENTER_FRAME, onLoop);
  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.    
  18.     grad.graphics.beginGradientFill(GradientType.LINEAR, [0xFFFFFF, 0xFFFFFF],  [1, 0], [0, (255 / img.width) * img.width / featherSize], m, SpreadMethod.PAD);
  19.    
  20.     grad.graphics.drawRect(0,0,img.width, img.height);
  21.     aChannel.draw(grad);
  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);
  32.     grad.graphics.clear();
  33.     grad.graphics.beginGradientFill(GradientType.LINEAR, [0xFFFFFF, 0xFFFFFF], [1, 0], [0, (255 / img.height) * img.height / featherSize],  m, SpreadMethod.PAD);
  34.    
  35.     grad.graphics.drawRect(0,0,img.width, img.height);
  36.     aChannel.draw(grad, grad.transform.matrix);
  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);
  44. addChild(new Bitmap(canvas));
  45.  
  46. var image:Loader = new Loader();
  47. image.load(new URLRequest("http://actionsnippet.com/imgs/paper.jpg"));
  48. image.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaded);
  49. var texture:BitmapData;
  50.  
  51. function onLoaded(evt:Event):void {
  52.     texture =  Bitmap(image.content).bitmapData;
  53.     addEventListener(Event.ENTER_FRAME, onLoop);
  54.     image.removeEventListener(Event.COMPLETE, onLoaded);
  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:



You can take a look at the swf here.

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...

Posted in BitmapData, graphics algorithms, pixel manipulation | 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
  7.     var char:Object ={posX:Math.random()*stage.stageWidth, posY:Math.random()*stage.stageHeight, velX:0, velY:0, rad:4, theta:Math.random()*6.28, thetaDest:Math.random()*6.28, mc: MovieClip(addChild(new MovieClip()))}
  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
  11.     addEventListener(Event.ENTER_FRAME, function(){
  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;
  39.     b.addEventListener(Event.ENTER_FRAME, function(){
  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.

Posted in misc, motion | Tagged , | Leave a comment

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.  
  6. addEventListener(Event.ENTER_FRAME, onLoop);
  7. function onLoop(evt:Event):void {
  8.     circle.x += (mouseX - circle.x) / 12;
  9. }

Posted in motion, one-liners | Tagged , | Leave a comment

Point.polar() Stars

Actionscript:
  1. [SWF(width=700, height=400, backgroundColor=0x000000, frameRate=30)]
  2.  
  3. var points:Array = new Array();
  4. var index:int = -1;
  5. function polar(thetaInc:Number, radius:Number):Point{
  6.     index++;
  7.     if (!points[index]) points[index] = 0;
  8.     return Point.polar(radius, points[index] += thetaInc)
  9. }
  10. ///////////////////////////////////////////////////
  11. // test it out:
  12.  
  13. var canvas:BitmapData = new BitmapData(700, 400, false, 0xFFFFFF);
  14.  
  15. addChild(new Bitmap(canvas, "auto", true));
  16.  
  17. var p0:Point = new Point(200, 200);
  18. var p1:Point = new Point(500, 200);
  19.  
  20. addEventListener(Event.ENTER_FRAME, onLoop);
  21. function onLoop(evt:Event):void {
  22.    
  23.     var rad:Point = polar(.05, 4);
  24.      
  25.     for (var i:int= 0; i<100; i++){
  26.        
  27.         // reset index;
  28.         index = -1;
  29.        
  30.         p0 = p0.add(polar(.025, 2).add(polar(-.05,rad.x)));
  31.         canvas.setPixel(p0.x, p0.y, 0x000000);
  32.        
  33.         p1 = p1.add(polar(.025, 2).add(polar(-.05,rad.x).add(polar(.1, rad.y))));
  34.         canvas.setPixel(p1.x, p1.y, 0x000000);
  35.     }
  36. }

This is pretty much the same as yesterdays... I just changed the way I use the polar() function to draw two more shapes:

Posted in BitmapData, motion, setPixel | Tagged , | Leave a comment

Playing with Curves Point.polar()

Actionscript:
  1. [SWF(width=600, height=500, backgroundColor=0x000000, frameRate=30)]
  2. var points:Array = new Array();
  3. var index:int = -1;
  4. function polar(thetaInc:Number, radius:Number):Point{
  5.     index++;
  6.     if (!points[index]) points[index] = 0;
  7.     return Point.polar(radius, points[index] += thetaInc);
  8. }
  9. ///////////////////////////////////////////////////
  10. // test it out:
  11.  
  12. var canvas:BitmapData = new BitmapData(600, 500, false, 0xFFFFFF);
  13.  
  14. addChild(new Bitmap(canvas, "auto", true));
  15.  
  16. var p0:Point = new Point(80, 100);
  17. var p1:Point = new Point(270, 100);
  18. var p2:Point = new Point(480, 40);
  19. var p3:Point = new Point(170, 180);
  20. var p4:Point = new Point(430, 300);
  21.  
  22. addEventListener(Event.ENTER_FRAME, onLoop);
  23. function onLoop(evt:Event):void {
  24.     for (var i:int= 0; i<100; i++){
  25.        
  26.         // reset index;
  27.         index = -1;
  28.        
  29.         p0 = p0.add(polar(.2, 4).add(polar(-.4,2).add(polar(.05, 1))));
  30.         canvas.setPixel(p0.x, p0.y, 0x000000);
  31.    
  32.         p1 = p1.add(polar(.1, 2).add(polar(-.2, 2).add(polar(.03, 1).add(polar(-.01,.5)))));
  33.         canvas.setPixel(p1.x, p1.y, 0x000000);
  34.      
  35.         p2 = p2.add(polar(.08, 3 ).add(polar(-.2, -12).add(polar(2, 10))));
  36.         canvas.setPixel(p2.x, p2.y, 0x000000);
  37.      
  38.         p3 = p3.add(polar(.08, 7).add(polar(-.2, -12).add(polar(2, 11))));
  39.         canvas.setPixel(p3.x, p3.y, 0x000000);
  40.        
  41.         p4 = p4.add(polar(.025, 2).add(polar(-.05,1)));
  42.         canvas.setPixel(p4.x, p4.y, 0x000000);
  43.     }
  44. }

The polar() function is the real trick here... the rest of the code just uses it to draw this:

The Point.polar() function is just a conversion from polar to cartesian coords:

Actionscript:
  1. x = radius * Math.cos(theta);
  2. y = radius * Math.sin(theta);

Posted in motion, setPixel | Tagged , | Leave a comment