Monthly Archives: April 2009

Quick Box2D

Actionscript:
  1. [SWF(backgroundColor = 0x333333)]
  2.  
  3. import com.actionsnippet.qbox.*;
  4.  
  5. // setting debug = true, will use the Box2D debug rendering
  6. var sim:QuickBox2D=new QuickBox2D(this, {debug:false, gravityY:10});
  7.  
  8. // creates static boxes on all sides of the screen
  9. sim.createStageWalls({lineAlpha:0, fillColor:0xFF9900});
  10.  
  11. // add 25 boxes
  12. for (var i:int = 0; i<25; i++){
  13.     var xp:Number = 3 + (i % 5);
  14.     var yp:Number = 1 + int( i / 5);
  15.     sim.addBox({x:xp, y:yp, width:1, height:1, fillColor: i * 10 <<16, lineAlpha:0, angularDamping:5});
  16. }
  17.  
  18. sim.addBox({x:7, y:10, width:3, height:.2, angle:-.3, density:0,lineAlpha:0, fillColor:0xFF9900});
  19.  
  20. sim.addCircle({x:3, y:14, radius:2, fillColor:0xCC0000, lineColor:0x333333});
  21.  
  22. sim.addPoly({x:13, y:5, verts:[[1,0,2,2,1,1.33],[1,0,1,1.33,0,2]], angle: .4, density:1});
  23.  
  24. // begins the simulation
  25. sim.start();
  26.  
  27. // all non-static objects can be dragged
  28. sim.mouseDrag();

I've been messing with Box2D for the past few weeks - I decided to create a library (QuickBox2D) for quick prototyping. This snippet makes use of this library, so in order to run it you'll need to download the zip included at the end of this post...

If you don't already know, Box2D is a great physics library created by Erin Catto. It was ported to AS3 by Matthew Bush and John Nesky. You can download the AS3 version of the library here.

Today's snippet creates this swf (click any image to view demo):

QuickBox2D

QuickBox2D simplifies Box2D instantiation and makes it easy to skin rigid bodies with Library assets... normally you need to do something like this to create a box in Box2D:

Actionscript:
  1. var bodyDef:b2BodyDef = new b2BodyDef();
  2. bodyDef.position.Set(3, 3);
  3. var boxDef:b2PolygonDef = new b2PolygonDef();
  4. boxDef.SetAsBox(1, 1);
  5. boxDef.density = 1;
  6. var body:b2Body = w.CreateBody(bodyDef);
  7. body.CreateShape(boxDef);
  8. body.SetMassFromShapes();

and this doesn't include setting up the physics world and the main loop to run the simulation... after writing a good deal of repetitive code I decided to make QuickBox2D. After writing lots of QuickBox2D style instantiation I decided to create an editor so that I could just draw circles, boxes, polygons and joints and then test and save them in real time (will be posting this editor in the near future). The next few posts will be about this mini-library and I'll be writing up some real documentation for it... as of now, it doesn't have any...

You can download Box2D here

You can download QuickBox2D here

and you can view some AS3 Box2D demos here

Posted in QuickBox2D, motion | Tagged , | 13 Comments

Random Equation Attractor

Actionscript:
  1. [SWF(width = 800, height = 800)]
  2. var a:Number = 0.19;
  3. var b:Number = .9;
  4. var c:Number = 1.3
  5. var xn1:Number = 5;
  6. var yn1:Number = 0;
  7. var xn:Number, yn:Number;
  8.  
  9. var scale:Number =40;
  10. var iterations:Number = 20000;
  11.  
  12. function f(x:Number):Number{
  13.     // too lazy to simplify this at the moment
  14.     return((x + .1 + x * (a - c) * x) / (1.1 + a * (c*c + a*a)  * x * x )) * 1.3;
  15. }
  16.  
  17. var canvas:BitmapData = Bitmap(addChild(new Bitmap(new BitmapData(800,800,false,0xEFEFEF)))).bitmapData;
  18.                                                                        
  19. addEventListener(Event.ENTER_FRAME, onLoop);
  20. function onLoop(evt:Event):void {
  21.    
  22.     canvas.fillRect(canvas.rect, 0xEFEFEF);
  23.      
  24.     c +=  ((stage.stageWidth/2 - mouseX) / 8000 - c) / 2;
  25.    
  26.     xn1 = 0;
  27.     yn1 = 0;
  28.     for (var i:int = 0; i<iterations; i++){
  29.           xn = xn1;
  30.           yn = yn1;
  31.          
  32.           xn1 = -xn - a + c +  f(yn);
  33.           yn1 = -xn + c * f(xn * yn);
  34.           canvas.setPixel( 380 + xn1 * scale, 450 + yn1 * scale, 0x000000);
  35.     }
  36. }

I was randomly messing around with strange attractors a few weeks back and this is one of the better results.... I arbitrarily altered equations until I got a nice result. You can move your mouse left and right to alter some of the params. Here is what it looks like when your mouse is in the middle of the screen:

Posted in BitmapData, misc, motion, pixel manipulation, setPixel | Tagged , | Leave a comment

Gradient Tooth

Actionscript:
  1. var canvas:BitmapData=new BitmapData(400,400,false,0x000000);
  2. addChild(new Bitmap(canvas));
  3.  
  4. var a:Number=-1.21;
  5. var r:Rectangle=new Rectangle(0,0,3,5);
  6. var halfWidth:Number=canvas.width/2;
  7. var halfHeight:Number=canvas.height/2;
  8.  
  9. render();
  10.  
  11. function render():void{
  12.     for (var x:Number = -2; x<=2; x+=.01) {
  13.         for (var y:Number = -2; y<=2; y+=.02) {
  14.    
  15.             // equation from : http://en.wikipedia.org/wiki/Bicuspid_curve
  16.             //(x^2 - a^2) * (x - a)^2 + (y^2 - a^2) * (y^2 - a^2) = 0
  17.    
  18.             // unpoptimized:
  19.             // var e:Number = (x*x - a*a) * (x-a)*(x-a) + (y*y-a*a) * (y*y-a*a);  
  20.             // optimized:
  21.             var x_a:Number=x-a;
  22.             // factoring: x^2 - a^2 = (x + a) * (x - a)
  23.             var y2_a2:Number =  (y + a) * (y - a);
  24.             var e:Number = (x + a) * x_a * x_a *  x_a +  y2_a2 * y2_a2;
  25.              
  26.                 r.x=halfWidth+y*50;
  27.                 r.y=halfHeight-x*100;
  28.                 var col:Number = e * 50;
  29.                 if (col <10){
  30.                     col = Math.abs(col) + 70;
  31.                     canvas.fillRect(r, col <<16 | col <<8 | col );
  32.                 }
  33.         }
  34.     }
  35. }

This is a variation on a post from a little while back.... it plots a modified Bicuspid that resembles a tooth:

Posted in Math, pixel manipulation, setPixel | Tagged , | Leave a comment

Random Walk Texture

Actionscript:
  1. package {
  2.  
  3.     [SWF(width=1000,height=1000)]
  4.     import flash.display.*;
  5.     import flash.events.*;
  6.     public class RandomWalkTexture extends Sprite {
  7.  
  8.         private var _canvas:BitmapData;
  9.         private var _populationNum:int=100;
  10.         private var _movers:Vector.<Mover>;
  11.         public function RandomWalkTexture() {
  12.             var sw:Number=stage.stageWidth;
  13.             var sh:Number=stage.stageHeight;
  14.             scaleX=scaleY=.25;
  15.             _canvas=new BitmapData(sw*4,sh*4,false,0x000000);
  16.             addChild(new Bitmap(_canvas));
  17.            
  18.             _movers = new Vector.<Mover>();
  19.             for (var i:int = 0; i<_populationNum; i++) {
  20.                 _movers[i]=new Mover(_canvas,sw*1.5+Math.random()*sw,sh*1.5+Math.random()*sh);
  21.             }
  22.             addEventListener(Event.ENTER_FRAME, onRun);
  23.         }
  24.         private function onRun(evt:Event):void {
  25.             for (var i:int = 0; i<200; i++) {
  26.                 for (var j:int = 0; j<_populationNum; j++) {
  27.                     _movers[j].run();
  28.                 }
  29.             }
  30.         }
  31.     }
  32. }
  33.  
  34. import flash.display.BitmapData;
  35. class Mover {
  36.     public var x:Number;
  37.     public var y:Number;
  38.     public var velX:Number;
  39.     public var velY:Number;
  40.     public var speed:Number;
  41.     private var _canvas:BitmapData;
  42.  
  43.     public function Mover(canvas:BitmapData, xp:Number, yp:Number) {
  44.         _canvas=canvas;
  45.         x=xp;
  46.         y=yp;
  47.         velX=0;
  48.         velY=0;
  49.         speed=Math.random()*5-2.5;
  50.     }
  51.     public function run():void {
  52.         x+=velX;
  53.         y+=velY;
  54.         _canvas.setPixel(x, y, 0xFFFFFF);
  55.         var dir:Number=int(Math.random()*4);
  56.         if (dir==0) {
  57.             velX=0;
  58.             velY=- speed;
  59.         } else if (dir == 1) {
  60.             velX=0;
  61.             velY=speed;
  62.         } else if (dir == 2) {
  63.             velX=- speed;
  64.             velY=0;
  65.         } else if (dir == 3) {
  66.             velX=speed;
  67.             velY=0;
  68.         }
  69.     }
  70. }

This snippet is meant to be run as a document class. Nothing special here... this is just something I found laying around - the actual bitmap being drawn is rather big, so I recommending right clicking (control clicking on mac) on the swf and to zoom in and out.

Here are a few images:




Posted in misc | Tagged , | 5 Comments

Swirl Gradient

Actionscript:
  1. var canvas:BitmapData=new BitmapData(200,200,false,0x000000);
  2. addChild(new Bitmap(canvas));
  3. scaleX=scaleY=2;
  4. var pixNum:int=canvas.width*canvas.height;
  5.  
  6. var xp:Vector.<int> = new Vector.<int>();
  7. var yp:Vector.<int> = new Vector.<int>();
  8. var radius:Vector.<Number> = new Vector.<Number>();
  9. var theta:Vector.<Number> = new Vector.<Number>();
  10. for (var i:int = 0; i<pixNum; i++) {
  11.     xp.push(i % 200);
  12.     yp.push(int(i / 200));
  13.     var dx:Number=100-xp[i];
  14.     var dy:Number=100-yp[i];
  15.     theta.push(Math.atan2(dy, dx));
  16.     radius.push(Math.sqrt(dx * dx + dy * dy)/20);
  17. }
  18.  
  19. addEventListener(Event.ENTER_FRAME, onLoop);
  20. function onLoop(evt:Event):void {
  21.     canvas.lock();
  22.     var n:Number = mouseX / 100;
  23.     for (var i:int = 0; i<pixNum; i++) {
  24.         var swirl:Number = 1+Math.sin(6*Math.cos(radius[i]) -n*theta[i]);
  25.         canvas.setPixel(xp[i], yp[i],  Math.abs(255 - swirl * 255));
  26.     }
  27.     canvas.unlock();
  28. }

This snippet creates a swirl gradient. While this snippet is not highly optimized, it does implement a basic optimization technique ... I cache some repetitive calculations in Vectors and then use them on the main loop.

I got the function for a swirl gradient from mathworld...

Posted in BitmapData, Math, pixel manipulation, setPixel | Tagged , | Leave a comment

2D Array to String

Actionscript:
  1. function format2D(a:Array):String {
  2.     var str:String="[";
  3.     for (var i:int = 0; i<a.length; i++) {
  4.         str+="["+a[i].toString()+"],";
  5.     }
  6.     str=str.substr(0,str.length-1);
  7.     str+="]";
  8.     return str;
  9. }
  10.  
  11. // test it out
  12. var array2D:Array = [[1,2,3], [4,5,6], [7,8,9]];
  13.  
  14. trace(array2D);
  15. trace(format2D(array2D));
  16.  
  17. /* outputs:
  18. 1,2,3,4,5,6,7,8,9
  19. [[1,2,3],[4,5,6],[7,8,9]]
  20.  
  21. */

When you trace a 2D array to the output window the actual structure of the array isn't clear. For some reason it just appears as a 1D array - this small function fixes that problem - it could also be used to save 2D arrays to text files etc...

Posted in string manipulation, strings | Tagged , | Leave a comment

Object Parsing (object from string #2)

Actionscript:
  1. var str:String = '{numA:100, numB:100, stringA:"hi there", object:{red:155, green:155, blue: 255}, array1D:[1, 2, 3, 4, 5, "six"], array2D:[[1,0,0], [0,1,0], [0,0,"z"]], color:0xFF0000}'
  2.  
  3. var obj:Object = toObject(str);//, true); // comment the "true" in for some debug info
  4.  
  5. // acess every value in the object for testing purposes
  6. trace(obj.numA);
  7. trace(obj.numB);
  8. trace(obj.stringA);
  9. trace(obj.object.red, obj.object.green, obj.object.blue);
  10. trace(obj.array1D +" testing access: " + obj.array1D[3]);
  11. trace(obj.array2D + " testing access: " + obj.array2D[1] + "  -  " + obj.array2D[2][2]);
  12. trace(obj.color);
  13.  
  14. /*outputs:
  15. 100
  16. 100
  17. hi there
  18. 155 155 255
  19. 1,2,3,4,5,six testing access: 4
  20. 1,0,0,0,1,0,0,0,z testing access: 0,1,0  -  z
  21. 16711680
  22. */
  23.  
  24. function toObject(str:String, debug:Boolean=false):Object{
  25.     var cmds:Array = new Array();
  26.     var stack:String = "";
  27.     // skip first {
  28.     str = str.replace(/^\s+\{|^\{/, "");
  29.     var obj:Object = new Object();
  30.     for (var i:int = 0; i<str.length; i++){
  31.         var char:String = str.charAt(i);
  32.         if (char == ":"){
  33.             cmds.push(["name:", stack])
  34.             stack = "";
  35.             char = "";
  36.         }else
  37.         if (char == "," || char == "}"){
  38.             if (stack != ""){
  39.               cmds.push(["value:", stack]);
  40.             }
  41.             stack = "";
  42.             char = "";
  43.         }else
  44.         if (char == '"'){
  45.             stack = '"';
  46.             for (j = i + 1; j <str.length; j++){
  47.                 char = str.charAt(j);
  48.                 stack+=char;
  49.                 i++;
  50.                 if (char == '"'){
  51.                      break;
  52.                 }
  53.             }
  54.             cmds.push(["value:", stack]);
  55.             stack = "";
  56.             char = "";
  57.         }else
  58.         if (char == "{"){
  59.             cmds.push(["object:", stack]);
  60.             for (var j:int = i; j <str.length; j++){
  61.                 char = str.charAt(j);
  62.                 stack+=char;
  63.                 i++;
  64.                 if (char == "}"){
  65.                      break;
  66.                 }
  67.             }
  68.             cmds.push(["value:", stack]);
  69.             stack = "";
  70.             char = "";
  71.         }else
  72.         if (char == "["){
  73.             cmds.push(["array:", stack]);
  74.             stack = "";
  75.             char = "";
  76.         }else if (char == "]"){
  77.             if (stack != ""){
  78.                 cmds.push(["value:", stack]);
  79.             }
  80.             stack = "";
  81.             char = "";
  82.             i++;
  83.         }
  84.         stack += char;
  85.     }
  86.     // show some debug info
  87.     if (debug){
  88.         for (i = 0; i<cmds.length; i++) trace(cmds[i]);
  89.     }
  90.     // build the object
  91.     var prop:String;
  92.     var arrayMode:Boolean = false;
  93.     var nest:int = 0;
  94.     for (i = 0; i<cmds.length; i++){
  95.         if (cmds[i][0] == "name:"){
  96.             prop = cmds[i][1].replace(/\s/g, "");
  97.             arrayMode = false;
  98.             nest = 0;
  99.         }else if (cmds[i][0] == "value:"){
  100.             if (arrayMode == false){
  101.               obj[prop] = valueType(cmds[i][1]);
  102.             }else{
  103.                 // populate array
  104.                 if (nest == 1){
  105.                   obj[prop].push(valueType(cmds[i][1]))
  106.                 }else{
  107.                   obj[prop][nest - 2].push(valueType(cmds[i][1]))
  108.                 }
  109.             }
  110.         }else if (cmds[i][0] == "object:"){
  111.             i++;
  112.             obj[prop] = toObject(cmds[i][1], debug);
  113.         }else if (cmds[i][0] == "array:"){
  114.             arrayMode = true;
  115.             nest++;
  116.             if (nest == 1){
  117.                 // create array
  118.                 obj[prop] = new Array()
  119.             }else{
  120.                 // nested array
  121.                 obj[prop].push(new Array());
  122.             }
  123.         }
  124.     }
  125.     return obj;
  126. }
  127.  
  128. function valueType(val:*):* {
  129.     if (isNaN(Number(val))) {
  130.            // remove leading and trailing white
  131.            // remove "" around strings
  132.            val = val.replace(/^s+|s+$/g,"").replace(/^"|"$/g,"");
  133.            //  see if it's a boolean
  134.            if (val == "true"){
  135.                val = true;
  136.            }else if (val == "false"){
  137.                val = false
  138.            }
  139.     } else {
  140.         val = Number(val);
  141.     }
  142.     return val;
  143. }

This rather large code snippet parses ActionScript style Object syntax. While this is by no means a complete parser - it was easy to write and saved me a great deal of time on a project recently....

I specifically needed support for 1D and 2D arrays as Object properties. If that weren't the case I would have used something simple like yesterdays method. The array support won't work with anything higher than a 2D array (for now... may fix that soon). For fun I also added nested Object support - this doesn't have any dimensional limitation so you can nest as many objects as you want. For instance.. this works just fine:

Actionscript:
  1. var gameUser:Object = toObject('{name:"Mr.S", alive:true, stats:{lives:100, points:1200, data:[100,12,40,12,90], plant:{branch:{leaves:["red, "green", "blue"]}}}');
  2.  
  3. trace(gameUser.stats.plant.branch.leaves[0]);
  4. trace(gameUser.stats.lives);
  5. // boolean support
  6. trace("not true is false: ", !gameUser.alive);
  7. /*outputs:
  8. red
  9. 100
  10. not true is false:  false
  11. */

You'll also notice the added boolean support in the above example. Which was suggested by katopz in the comments of yesterdays post.

Definitely need to add a word of warning here... I wouldn't be surprised if there were a bug or two lurking in this code. The Objects I've been parsing with it are all quite similar... so use at your own risk.

UPDATEs - Known Issues:
1) fixed a bug where if a String property contains a ,{}[] or : character the parser failed.

Posted in dynamic, string manipulation, strings | Tagged , | 4 Comments

Object from String

Actionscript:
  1. var str:String='{x: 10, y:10, width:100, heigth:100, name:"myClip", type:"clip"}';
  2.  
  3. var obj:Object=toObject(str);
  4.  
  5. trace(obj.x + obj.width, obj.name, obj.type);
  6.  
  7. function toObject(str:String):Object {
  8.     str=str.replace(/\{|\}/g,"");
  9.     // to an array of name value pairs [0] = name, [1] = value etc...
  10.     var pairs:Array=str.split(/\:|\,\s+/);
  11.     var obj:Object = new Object();
  12.     for (var i:int = 0; i<pairs.length; i+=2) {
  13.         obj[pairs[i]]=numOrString(pairs[i+1]);
  14.     }
  15.     return obj;
  16. }
  17. function numOrString(val:*):* {
  18.     if (isNaN(Number(val))) {
  19.         if (val.charAt(0) == '"' && val.charAt(val.length - 1) == '"'){
  20.             val = val.substr(1, val.length - 2);
  21.         }
  22.     } else {
  23.         val=Number(val);
  24.     }
  25.     return val;
  26. }

A very limited way to parse an object from a string... Tomorrow I'll post a better version of this that's a good deal more complex and doesn't really use regular expressions... This works nicely if you don't have arrays as Object properties...

Posted in dynamic, string manipulation, strings | Tagged , | 2 Comments

Infinity Scroller (repeating navigation)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
var buttonsWidth:Number = 0;
var buttonsA:Sprite = new Sprite();
var buttonsB:Sprite = new Sprite();
var nav:Sprite = new Sprite();
 
var buttonData:Array = ["one", "two", "three", "four", "five", "six", 
                                    "seven", "eight", "nine", "ten"];
 
buildNav();
 
function buildNav():void{
	nav.addChild(buttonsA);
        nav.addChild(buttonsB);
        addChild(nav);
	buildButtons(buttonsA);
	buttonsWidth = buttonsA.width;
	buildButtons(buttonsB);
	buttonsB.x = buttonsWidth;
}
 
function buildButtons(container:Sprite):void{
	for (var i:int = 0; i<buttonData.length; i++){
		var b:MovieClip = new MovieClip();
	        with(b.graphics){
			lineStyle(0,0x000000);
			beginFill(0xCCCCCC);
			drawRect(0,0,100,30);
		}
		b.x = i * b.width;
		var txt:TextField = new TextField();
		txt.scaleX = txt.scaleY = 1.5
		txt.selectable = false;
		txt.multiline = false;
		txt.autoSize = TextFieldAutoSize.LEFT;
		txt.mouseEnabled = false;
		txt.x = 3;
		txt.text = buttonData[i];
		b.buttonMode = true;
		b.addChild(txt)
	        container.addChild(b);
	}
}
 
var velX:Number = 0;
var navSpeed:Number = 8;
var leftSide:Number = stage.stageWidth / 3;
var rightSide:Number = leftSide * 2;
addEventListener(Event.ENTER_FRAME, onRunNav);
function onRunNav(evt:Event):void {
	if (mouseY < 100){
		if (mouseX  < leftSide){
			velX = navSpeed;
		}
		if (mouseX > rightSide){
			velX = -navSpeed;
		}
		if (nav.x < -buttonsWidth){
			nav.x = -navSpeed;
		}
		if (nav.x > -navSpeed){
			nav.x = -buttonsWidth 
		}
	}
	velX *=.9;
	nav.x += velX;
}

This snippet creates a navigation that will scroll to the left or right forever - the buttons will simply repeat. I'm not a big fan of this kind of navigation - especially if you have lots of buttons, but it seems to be a common request. This technique can be modified for use in a side-scroller style game.

Just added a new syntax highlighter, please posts comments if you have any issues viewing this snippet.

Posted in UI, motion | Tagged , | 4 Comments

Testing New Code Highlighter

1
2
var sprite:Sprite = new Sprite();
addChild(sprite);

Just testing a new highlighter... the site may have some weird issues for the next few minutes

UPDATE: Seems to be working, please let me know via the comments on this post if you see any code highlighting issues.

The new code highlighter won't copy and paste line numbers into the timeline. For old posts you'll still need to click the PLAIN TEXT button above each snippet.

Posted in Uncategorized | Leave a comment