Category Archives: dynamic

Command Draw Source

Actionscript:
  1. [SWF(width = 600, height = 500, frameRate=30, background = 0xFFFFFF)]
  2.  
  3. var cmd:String = "1000 small orange circles, 9000 black lines,3 large white circles"
  4. // try some of these commands:
  5. //"300 small red triangles and 2 big orange circle 3 big black lines";
  6. //"100 big black triangles, ten small white rectangles 1 big white circle and 1 big gray poly";
  7. // "300 small red triangles and 2 big orange circle 3 big black lines";
  8. //"10 big black circles 1000 big white lines 100 small white rects 1 big red circle and 1 green poly"
  9. stage.align = "TL"
  10. var msk:Shape = new Shape();
  11. with(msk.graphics) beginFill(0x00FF00), drawRect(0,0,600, 400);
  12. this.mask = msk;
  13. var amount:Number;
  14. var color:uint = 0;
  15. var shape:String;
  16.  
  17. var hexLookup:Object = {red:0xFF0000, green:0x00FF00, blue:0x0000FF, yellow:0xFFFF00, orange:0xFFCC00, white:0xFFFFFF, gray:0xCCCCCC, grey:0xCCCCCC, black:0x000001};
  18. var sizeLookup:Object = {large:true, big:true, small:true, tiny:true};
  19. var defaultSize:Number = 50;
  20. var size:Number = defaultSize;
  21. var halfSize:Number = size / 2;
  22. var circles:Function = circle;
  23. var ovals:Function = oval, ellipse:Function = oval;
  24. var rects:Function = rect, rectangle:Function = rect, rectangles:Function = rect;
  25. var lines:Function = line;
  26. var triangles:Function = triangle;
  27. var polygon:Function = poly, polygons:Function = poly;
  28. var large:Function = big;
  29. var tiny:Function = small;
  30.  
  31. parse();
  32. function parse():void {
  33.     amount = 1;
  34.     color = 0x000000;
  35.     shape = "circle";
  36.     var words:Array = cmd.split(/[\W]+/g)
  37.     for (var i:int = 0; i<words.length; i++){
  38.         var w:* = words[i];
  39.         if (isNaN(Number(w))){
  40.             if (hexLookup[w]){
  41.                 color = hexLookup[w];
  42.                 trace(w, "color");
  43.             }else
  44.             if (sizeLookup[w]){
  45.                 this[w]();
  46.             }else
  47.             if (this[w]){
  48.                 for (var j:int = 0; j<amount; j++){
  49.                    this[w]();
  50.                 }
  51.                 color = 0x000000;
  52.                 size = defaultSize;
  53.                 trace(w, "command");
  54.             }
  55.         }else{
  56.             trace(w, "number");
  57.             amount = w;
  58.         }
  59.     }
  60. }
  61. function makeShape(p:Array):void{
  62.         var s:Shape = Shape(addChild(new Shape()));
  63.          for (var i:int = 0; i<p.length; i++) {
  64.             s.graphics[p[i][0]].apply(graphics,p[i].splice(1));
  65.          }
  66.         s.rotation = Math.random() * 360;
  67.         s.x = Math.random() * stage.stageWidth;
  68.         s.y = Math.random() * stage.stageHeight;
  69. }
  70.  
  71. function circle():void{
  72.       makeShape([["beginFill",color], ["drawCircle",0,0,Math.random() * halfSize + halfSize]]);
  73. }
  74. function oval():void{
  75.       makeShape([["beginFill",color],["drawEllipse", 0,0,Math.random() * size + halfSize]]);  
  76. }
  77. function square():void{
  78.         var s:Number = Math.random() * halfSize + halfSize;
  79.         var p:Number = -s/2;
  80.         makeShape([["beginFill",color],["drawRect", p, p, s, s]]);  
  81. }
  82. function rect():void{
  83.         var w:Number = Math.random() * halfSize + halfSize;
  84.         var h:Number = Math.random() * halfSize + halfSize;
  85.         makeShape([["beginFill",color],["drawRect", -w/2, -h/2, w, h]]);
  86. }
  87. function line():void{
  88.     var s:Number = size * 2;
  89.     makeShape([["lineStyle",Math.random()*3, color],["lineTo", Math.random()*s - size, Math.random()*s - size]])
  90. }
  91. function triangle():void {
  92.      var s:Number = size * 2;
  93.      makeShape([["beginFill",color],["lineTo", Math.random()*s - size, Math.random()*s - size], ["lineTo", Math.random()*s - size, Math.random()*s - size]]);
  94. }
  95. function poly():void {
  96.      var s:Number = size * 2;
  97.      var cmds:Array = [["beginFill",color]]
  98.      var num:Number = int(Math.random()*8) + 2;
  99.      for (var i:int = 0; i<num; i++){
  100.           cmds.push(["lineTo", Math.random()*s - size, Math.random()*s - size]);
  101.      }
  102.      makeShape(cmds);
  103. }
  104. function big():void{
  105.     size = 100 + Math.random() * 40;
  106.     halfSize = size / 2;
  107. }
  108. function small():void {
  109.     size = 3 + Math.random() * 20;
  110.     halfSize = size / 2;
  111. }

I've been meaning to post this source for a long time. It's a project I created for shapevent called Command Draw. It allows you to use simple sentence structure to create textures and patterns.

See it in action here (this one has some minimal UI and uses flashvars for the command string).


As a side note, this is the 200th post on ActionSnippet.com

Also posted in Graphics, strings | Tagged , | 3 Comments

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.

Also posted in 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...

Also posted in string manipulation, strings | Tagged , | 2 Comments

Object Argument w/ Defaults

Actionscript:
  1. var boxDefaults:Object = {x:10, y:10, width:100, height:100, lineThickness:0, lineColor:0x000000, lineAlpha:1, fillColor:0xCCCCCC, fillAlpha:1}
  2. function drawBox(params:Object=null):void {
  3.     var p:Object=setDefaults(boxDefaults, params);
  4.     graphics.lineStyle(p.lineThickness, p.lineColor, p.lineAlpha);
  5.     graphics.beginFill(p.fillColor, p.fillAlpha);
  6.     graphics.drawRect(p.x, p.y, p.width, p.height);
  7. }
  8.  
  9. function setDefaults(defaults:Object, params:Object=null):Object {
  10.     if (params==null) {
  11.         params = new Object();
  12.     }
  13.     for (var key:String in defaults) {
  14.         if (params[key]==null) {
  15.             params[key]=defaults[key];
  16.         }
  17.     }
  18.     return params;
  19. }
  20.  
  21. // test it out... notice that all object properties are optional and have default values                                         
  22. drawBox();
  23.  
  24. drawBox({x:200, y:200, lineColor:0xFF0000, lineThickness:2, fillColor:0xCCCC00});
  25.  
  26. drawBox({x:200, y:320, width:50, height:150, lineAlpha:0, fillColor:0x416CCF});

This is a technique I've been using recently... inspired by tweening engines. I find this to be suitable when a function or object constructor has lots and lots of arguments (80% of the time if I have a function or object constructor with too many arguments I re-think my design, but every now and then I use this technique).

Basically, the function or object constructor takes one argument of type Object - once passed into the function this Object argument is passed to the setDefault() function which populates it with any properties that it's missing - each property has a default value. As a result you end up with an easy to read function call with a variable number of arguments and well thought out default values.

This snippet just draws a box (not very interesting or usefull) - I wanted to showcase the technique using a simple function. As a real world example... I recently used this technique in a mini-library I created for use with Box2D... will be posting the library in the next few days.... it's a library for fast prototyping and custom rendering.

Also posted in functions | Tagged , | 3 Comments

Flashvars

Actionscript:
  1. // variable is passed into the swf via Javascript (most likely swfObject)
  2. // myswf.swf?myFlashVar="a new value"
  3.  
  4. var myFlashVar:String = "Some Default Value";
  5. if (root.loaderInfo.parameters.myFlashVar){
  6.    myFlashVar = root.loaderInfo.parameters.myFlashVar;
  7. }

Getting at flashvars in AS3 requires a bit more typing than it did in AS2. Above is a technique I find myself using from time to time. Usually for paths to xml or dynamic callouts (large buttons with text, an image and a link that change frequently).

Also posted in misc | Tagged , | Leave a comment

Object.constructor()

Actionscript:
  1. var Box:Function = {
  2.     constructor : function(color:uint, w:Number, h:Number):void {
  3.         this.color = color;
  4.         this.s = new Shape();
  5.         with(this.s.graphics) beginFill(this.color), drawRect(0,0,w,h);
  6.         addChild(this.s);
  7.        
  8.         this.setLoc = function(x:Number, y:Number):void{
  9.             this.s.x = x;
  10.             this.s.y = y;
  11.        }
  12.     }
  13. }.constructor;
  14.  
  15. var box0:Object = new Box(0xFF0000, 100, 100);
  16.  
  17. box0.setLoc(100, 10);
  18.  
  19. var box1:Object = new Box(0x000000, 50, 50);
  20.  
  21. box1.setLoc(210, 10);

This snippet makes use of Object.constructor() to allow creation of Object instances using the new keyword. This is for fun only, I don't recommend this over actual Classes.

Also posted in OOP, functions, misc | Tagged , | Leave a comment

Square Bracket Syntax & Typecasting

Actionscript:
  1. addChild(new TextField());
  2. getChildAt(0)["text"] = "Hello World";

Notice that square bracket syntax makes it so we don't need to typecast. Take a look at the other way:

Actionscript:
  1. addChild(new TextField());
  2. TextField(getChildAt(0)).text = "Hello World";

Typecasting is the way to go.... the square bracket technique is just an interesting trick.

I wrote this after somehow stumbling on this very entertaining page - it shows hello world written in approximately 200 different languages...

Also posted in misc | Tagged , | Leave a comment

“in” Operator

Actionscript:
  1. var obj:Object = {name: "Joe", hobby: "Guitar", age:"80"};
  2.  
  3. if ("name" in obj){
  4.     trace(obj, " has a name property");
  5. }
  6.  
  7. if ("x" in obj == false){
  8.     trace(obj, " doesn't have an x property");
  9. }
  10.  
  11.  
  12. var mySprite:Sprite = new Sprite();
  13.  
  14. if ("currentFrame" in mySprite == false){
  15.     trace(mySprite, "does not have a currentFrame property");
  16. }

The "in" operator can be used to check if an object has a specific property. In the above example I test a standard Object instance and a Sprite instance for a few different properties.

I could see this operator being used when dealing with * (wildcard) datatypes and dynamic style code....

Also posted in Operators | Tagged , | Leave a comment

Graphics Class Methods in XML

Actionscript:
  1. // for simplicity I left this XML inline, this will work exactly the same if it were external
  2. var program:XML=<body>
  3.                 <draw>
  4.                   <![CDATA[
  5.                    beginFill(0xFF0000);
  6.                    drawCircle(100,100,50);
  7.                    endFill();
  8.                    lineStyle(0, 0x666666);
  9.                    moveTo(100, 100);
  10.                    lineTo(200, 200);
  11.                    moveTo(300, 200);
  12.                    curveTo(350, 300, 400, 200);
  13.                    lineStyle(0, 0x0000FF);
  14.                    drawRect(200, 50,100,100) ;
  15.                     ]]>
  16.                 </draw>
  17. </body>;
  18.  
  19. // parse and run the Graphics class commands from the XML
  20. render(parseFunctions(program.draw.toString()));
  21.  
  22. function parseFunctions(dat:String):Array{
  23.     var a:Array = dat.split(";") ;
  24.     for (var i:int = 0; i<a.length-1; i++){
  25.         a[i] = a[i].split(/\(\)|\(|\)/g);
  26.         var f:String = a[i][0] = a[i][0].replace(/\s/g,"");
  27.         a[i] = a[i].splice(0, a[i].length - 1);
  28.         if (a[i].length> 1){
  29.          a[i] = a[i][1].split(",");
  30.          a[i].unshift(f);
  31.         }
  32.     }
  33.     return a.splice(0,a.length - 1);
  34. }
  35. function render(p:Array):void {
  36.     for (var i:int = 0; i<p.length; i++) {
  37.         graphics[p[i][0]].apply(graphics,p[i].splice(1));
  38.     }
  39. }

The above code builds on yesterdays post by showing how one could potentially store graphics class method calls in XML using a few regular expressions and Function.apply().

The parseFunctions() function reads through the CDATA string and formats it in a 2D array that looks like this:

Actionscript:
  1. [[beginFill, 0xFF0000], [drawCircle, 100, 100, 50], etc...]

The render() function reads through this 2D array, using the first value of each nested array as the function and the remaining values as arguments...

As is this won't really work with most of the new fp10 graphics methods...

Also posted in Graphics, XML, external data, functions, string manipulation, strings | Tagged , | Leave a comment

Dynamic Graphics and Function.apply()

Actionscript:
  1. var cmds:Array = [["lineStyle", 0, 0xFF0000], ["drawCircle",100, 100, 50], ["drawRect", 50, 50, 100, 100]];
  2. cmds.push(["drawCircle", 100, 100, 70]);
  3. cmds.push(["beginFill",  0x555555]);
  4. cmds.push(["drawRoundRect", 80, 80, 40, 40, 10, 10]);
  5. cmds.push(["endFill"]);
  6.  
  7. render(cmds);
  8.  
  9. function render(p:Array):void {
  10.     for (var i:int = 0; i<p.length; i++) {
  11.         graphics[p[i][0]].apply(graphics,p[i].splice(1));
  12.     }
  13. }

The above creates a function called render() that takes a 2D array of Graphics class methods and then runs them. This is a very interesting technique, specifically if you'd like to write Graphics class method calls in an XML or txt file and then have them run on a given DisplayObject in flash.

I've been thinking about the best way to do this for awhile... I started off doing something very convoluted and then realized that I could use Function.apply()....

Tomorrow I'll post a snippet showing how to use this function in conjunction with XML.

Also posted in Graphics, functions | Tagged , | 2 Comments