# Monthly Archives: April 2009

Actionscript:
1. var canvas:BitmapData=new BitmapData(200,200,false,0x000000);
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.
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...

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

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

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