Recent Updates RSS Toggle Comment Threads | Keyboard Shortcuts

  • alyoka 2:16 pm on Monday, May 17th, 2010 Permalink | Reply  

    Utils: Parsing XML 

    “The major difference between a thing that might go wrong and a thing that cannot possibly go wrong is that when a thing that cannot possibly go wrong goes wrong it usually turns out to be impossible to get at or repair” – Douglas Adams, Mostly harmless


    What a waste of time!

    I keep seeing developers writing a lot of XML – one to define this, one to define that. This is not too bad. What’s bad is that these XML files are then loaded in different parts of the application, where data is carefully (read: custom) pulled out. I know, E4X has made dealing with XML much easier, but why bother custom-parsing it at all? It’s boring, time-consuming, and most important: code becomes dependent on the data format.


    What if the data format was to be changed?

    It could be sent as JSON or even binary, but you’ve never considered that. Oh no! The whole data layer has to be restructured for the new format. I can hear the developer scream: “But I’ve already done it for XML!”


    Why care about where data comes from?

    Solution is to separate your application’s data structure from the data source. This can be done using DTO and DAO design patterns:
    - DataAccessObject (DAO) abstracts data access implementation to enable transparent access to the data source [1]
    - DataTransferObject (DTO) carries data between application’s subsystems [2]


    What you get

    - All data access and parsing are centralized in one place
    - Reduced code complexity in business objects
    - Implementing a new data format becomes very simple – just create a new DAO, which will access and serialize data from that specific format, no business logic has to be changed
    - Enables easy Unit testing / bug fixing
    - Being very generic, DAOs can be reused in other projects
    - An extra layer of objects (DAOs and DTOs), which is seen by some developers as a waste of time. I see it rather as creating a contract between data source and data client, which leads to cleaner, easier to maintain and more flexible code. It will save you a lot of time later on the project.


    To the point

    We have been using this approach for quite a while now and are happy with the results. We have created a number of DAOs for different connection types and a few parsing strategies to format the data we receive into DTOs.

    Here is our generic XML parser:

    XMLParser.as

    package ch.forea.parsing {
      import ch.forea.dto.AbstractDTO;
      import flash.utils.Dictionary;
      import flash.utils.describeType;
      import flash.utils.getDefinitionByName;

      public class XMLParser {
        public function parse(xml:XMLList, responseType:String):* {
          //1. instantiate response class
          var dto : *;
          try{
            var responseClass:Class = getDefinitionByName(responseType) as Class;
          }catch(e:Error){
            throw new Error("XMLParser.request: couldn't instantiate "+responseType);  
          }
          dto = new responseClass();

          //2. fill out public vars and accessors of the new instance with data from xml
          //2.1. create a dictionary (dict[name]=type) based on the response class's public variables and accessors
          var dtoDescription:XML = describeType(dto);
          var variables:XMLList = dtoDescription..variable;
          var accessors:XMLList = dtoDescription..accessor;
          var dtoprops:Dictionary = new Dictionary();
          var child:XML;
                for each (child in variables){
                    dtoprops[child.@name.toString()] = child.@type.toString();
          }
          for each (child in accessors){
             if(child.@access.toString() == "readwrite"){
                      dtoprops[child.@name.toString()] = child.@type.toString();
             }
          }
         
          //2.2. for each of the public vars/accessors find an XML tag with the same name,
          //     parse tag's value and assign it to the the response dto's variable/accessor
          var value:XMLList;
          var type:String;
          for(var propertyName:String in dtoprops){
            value = xml[propertyName];
            delete xml[propertyName];
            if(!value.length()) {
              if(xml.attribute(propertyName).toString() != ""){
                value = xml.attribute(propertyName);
                delete xml.@[propertyName];
              }
            }
            type = dtoprops[propertyName];
            if(value && value.toXMLString() != "") {
              try{
                dto[propertyName] = parseSingleObject(XMLList(value), type);
              }catch(e:Error){
                throw new Error("XMLParser.parseXMLResponse() failed, e: "+e);
              }
            }
          }
         
          //3. if response class is dynamic, add extra properties from xml as dynamic properties
          //NOTE: parses ONLY through attributes and interprets them as Strings!!!
          if(dtoDescription.@isDynamic.toString() == "true") {
            var attName:String;
            for each(var node:XML in xml.attributes()){
              if(node.toString() != ""){
                attName = node.name().toString().replace("@","");
                dto[attName] = node.toString();
              }
            }
          }
         
          return dto;
        }
       
        private function parseSingleObject(value:XMLList, type:String) : * {
          var primitiveTypes : RegExp = /^Boolean$|^int$|^Number$|^String$|^uint$/;
          var array:RegExp = /^Array$/;
          var vector:RegExp = /^__AS3__.vec::Vector.</;
         
          var intCheck:RegExp = /^-{0,1}\d+$/;
          var uintCheck:RegExp = /^\d+$/;
          var numberCheck:RegExp = /^-{0,1}\d*\.{0,1}\d+$/;
          var booleanCheck:RegExp = /^1|0|true|false$/i;
         
          var vectorToClassName:RegExp = /(__AS3__.vec::Vector.<)([A-Za-z0-9.]*)(?:::)*([A-Za-z0-9]*)(>)/g;
          var elements:XMLList;
          var child:*;
         
          //PRIMITIVES
          if(primitiveTypes.test(type)) {

            //just fill out
            switch(type){
              case "int":
                if(!intCheck.test(value)) throw new Error("XMLParser.parseSingleObject property type value:" + value + " should be of type '" + type + "'. Correct xml");
                return new int(parseInt(value.toString()));
              break;
              case "uint":
                if(!uintCheck.test(value)) throw new Error("XMLParser.parseSingleObject property type value:"+value+" should be of type '"+type+"'. Correct xml");
                return new uint(parseInt(value.toString()));
              break;
              case "Number":
                if(!numberCheck.test(value)) throw new Error("XMLParser.parseSingleObject property type value:"+value+" should be of type '"+type+"'. Correct xml");
                return Number(value.toString());
              break;
              case "String":
                return value.toString();
              break;
              case "Boolean":
                if(!booleanCheck.test(value)) throw new Error("XMLParser.parseSingleObject property type value:"+value+" should be of type '"+type+"'. Correct xml");
                return (value.toString() == "true" || value.toString() == "1");
              break;
            }
         
          //ARRAYS
          }else if(array.test(type)){
            var a:Array = [];
            if((value as XMLList).hasComplexContent()){
              //parse through elements and fill them with xml values
              elements = value.children();
              for each(child in elements){
                a.push(child);
              }
            }else{
              //assume value is a comma delimited string - split it and fill out array
              a = value.toString().split(",");
            }
            return a;
           
          //VECTORS
          }else if(vector.test(type)){
            //instantiate vector and parse each of its members
            var c:Class;
            var v:*;
           
            try{
              c = getDefinitionByName(type) as Class;
            }catch(e:Error){
              throw new Error("XMLParser.parseSingleObject, class could not be instantiated: "+type+", error: " + e.message);
            }
            v = new c();
           
            var valueType:String = type.replace(/(__AS3__.vec::Vector.<)([A-Za-z0-9.:]*)(>)/, "$2");
            if(value.hasComplexContent()){
              elements = value.children();
              for each(child in elements){
                v.push(parseSingleObject(XMLList(child), valueType));
              }
              return v.length ? v : null;
            } else{
              //assume value is a comma delimited string - split it and fill out array
              var values:Array;
              if(value.toString() != ""){
                values =  value.toString().split(",");
              }
              for each(var val:String in values) {
                v.push(parseSingleObject(XMLList("<primitive>"+val+"</primitive>"), valueType));
              }
              return v.length ? v : null;
            }
           
          //CUSTOM OBJECTS
          }else{
            return parse(XMLList(value), type);
          }
        }
      }  
    }



    XML parser has a parse method, which requires two arguments:
    - an XMLList object to parse,
    - a qualified classname of a DTO the xml should be parsed to.

    Briefly, the parser instantiates the DTO class, runs through its public variables and fills them with values from identically named xml tags.

    Note, that:
    - XML parser deals only with custom DTOs, where all the properties are defined, anonymous objects will not be parsed
    - properties of primitive type can be written as either childNodes or attributes:

    <testCustomObject><greeting>hello</greeting></testCustomObject>

    and

    <testCustomObject greeting="hello"/>

    are interchangeable and will be both parsed as testCustomObject.greeting = “hello”
    - using Vectors instead of Arrays (in your DTOs) makes it possible to determine type of data contained in the Vector and correctly parse it.


    What you get

    Here is an example of parsing xml to objects of different types:

    ParserTest.as

    package ch.forea.test {
      import ch.forea.parsing.XMLParser;
      import flash.display.Sprite;

      public class ParserTest extends Sprite {
        public function ParserTest() {
          var xml:XML = <xml>
            <testString>hello world</testString>
            <testInt>-10</testInt>
            <testUint>10</testUint>
            <testNumber>10.5</testNumber>
            <testBoolean>true</testBoolean>
            <testCustomObject>
              <greeting>hello world!</greeting>
            </testCustomObject>
            <testVector1>a,b,c,d</testVector1>
            <testVector2>
              <elem>a</elem>
              <elem>b</elem>
              <elem>c</elem>
              <elem>d</elem>
              <elem>e</elem>
              <elem>f</elem>
            </testVector2>
            <testVectorVector1>
              <vector>g,h,i,j,k,l</vector>
              <vector>m,n,o,p</vector>
            </testVectorVector1>
            <testVectorVector2>
              <vector>
                <testCustomObject>
                  <greeting>hey</greeting>
                </testCustomObject>
                <testCustomObject>
                  <greeting>hi</greeting>
                </testCustomObject>
                <testCustomObject>
                  <greeting>good morning</greeting>
                </testCustomObject>
              </vector>
              <vector>
                <testCustomObject>
                  <greeting>hello</greeting>
                </testCustomObject>
                <testCustomObject>
                  <greeting>nice weather!</greeting>
                </testCustomObject>
              </vector>
            </testVectorVector2>
          </xml>;
         
          var xmlParser:XMLParser = new XMLParser();
          var dto:TestDTO = xmlParser.parse(XMLList(xml), "ch.forea.test.TestDTO") as TestDTO;
          trace(dto);
        }
      }
    }

    TestDTO.as

    package ch.forea.test {
      import ch.forea.dto.AbstractDTO;

      public class TestDTO extends AbstractDTO {
        public var testString:String;
        public var testInt:int;
        public var testUint:uint;
        public var testNumber:Number;
        public var testBoolean:Boolean;
        public var testCustomObject:CustomObjectDTO;
        public var testVector1:Vector.<String>;
        public var testVector2:Vector.<String>;
        public var testVectorVector1:Vector.<Vector.<String>>;
        public var testVectorVector2:Vector.<Vector.<CustomObjectDTO>>;
      }
    }

    CustomObjectDTO.as

    package ch.forea.test {
      import ch.forea.dto.AbstractDTO;

      public class CustomObjectDTO extends AbstractDTO {
        public var greeting:String;
      }
    }

    Result trace

    ch.forea.test::TestDTO(
      testBoolean = true,
      testUint = 10,
      testCustomObject = ch.forea.test::CustomObjectDTO(greeting = hello world!),
      testVectorVector1 = g,h,i,j,k,l,m,n,o,p,
      testVector2 = a,b,c,d,e,f,
      testNumber = 10.5,
      testVectorVector2 = ch.forea.test::CustomObjectDTO(greeting = hey),
                          ch.forea.test::CustomObjectDTO(greeting = hi),
                          ch.forea.test::CustomObjectDTO(greeting = good morning),
                          ch.forea.test::CustomObjectDTO(greeting = hello),
                          ch.forea.test::CustomObjectDTO(greeting = nice weather!),
      testString = hello world,
      testInt = -10,
      testVector1 = a,b,c,d)

    Quite handy, isn’t it?


    XML creator

    Now that we don’t want to deal with XML anymore, we’ll stop writing it by hand and start auto generating it based on our DTOs. It’s a reverse of parsing XML:

    XMLCreator.as

    package ch.forea.utils {
      import flash.utils.Dictionary;
      import flash.utils.describeType;
      import flash.utils.getQualifiedClassName;

      public class XMLCreator {
        private var primitiveTypes : RegExp = /^Boolean$|^int$|^Number$|^String$|^uint$/;
       
        public function parse(dto:*, name:String = null):XML {
          var dtoName:String = name ? name : getQualifiedClassName(dto).replace(/(.*)\:/,"");
          var xml:XML = new XML("<"+dtoName+"/>");

          //1. list dto's public variables and accessors in a dictionary (dict[name]=type)
          var dtoDescription:XML = describeType(dto);
          var variables:XMLList = dtoDescription..variable;
          var accessors:XMLList = dtoDescription..accessor;
          var dtoprops:Dictionary = new Dictionary();
          var child:XML;
                for each (child in variables){
                    dtoprops[child.@name.toString()] = child.@type.toString();
          }
          for each (child in accessors){
             if(child.@access.toString() == "readwrite"){
                      dtoprops[child.@name.toString()] = child.@type.toString();
             }
          }
         
          //2. for each of the public vars/accessors create an XML node with the same name and parse the value
          var type:String;
          for(var propertyName:String in dtoprops){
            type = dtoprops[propertyName];
            //if value is a primitive type, assign it to an attribute to save space
            if(primitiveTypes.test(type)){
              xml.@[propertyName] = dto[propertyName].toString();
            } else{
              xml.appendChild(parseSingleObject(dto[propertyName], propertyName, type));
            }
          }
          return xml;
        }
       
        private function parseSingleObject(value:*, name:String, type:String) : XML {
          var xml:XML = new XML("<"+name+"/>");
         
          var array:RegExp = /^Array$/;
          var vector:RegExp = /^__AS3__.vec::Vector.</;
         
          //PRIMITIVES
          if(primitiveTypes.test(type)) {
            xml.appendChild(value.toString());
          //ARRAYS
          }else if(array.test(type)){
            for each(var obj:* in value){
              xml.appendChild(parseSingleObject(obj,"element","object"));
            }
          //VECTORS
          }else if(vector.test(type)){
            var valueType:String = type.replace(/(__AS3__.vec::Vector.<)([A-Za-z0-9.:]*)(>)/, "$2");
            for each(var obj:* in value){
              xml.appendChild(parseSingleObject(obj,"element",valueType));
            }        
          //CUSTOM OBJECTS
          }else{
            return parse(value, name);
          }
          return xml;
        }
      }  
    }

    Now, let’s add a few lines to ParserTest.as and compare the original handwritten XML to the XMLCreator result:

    Test

    var xmlCreator:XMLCreator = new XMLCreator();
    var newXml:XML = xmlCreator.parse(dto);
    trace(newXml);

    Test result

    <TestDTO testString="hello world" testBoolean="true" testInt="-10" testNumber="10.5" testUint="10">
       <testCustomObject greeting="hello world!"/>
       <testVector1>
         <element>a</element>
         <element>b</element>
         <element>c</element>
         <element>d</element>
       </testVector1>
       <testVectorVector1>
         <element>
           <element>g</element>
           <element>h</element>
           <element>i</element>
           <element>j</element>
           <element>k</element>
           <element>l</element>
         </element>
         <element>
           <element>m</element>
           <element>n</element>
           <element>o</element>
           <element>p</element>
         </element>
       </testVectorVector1>
       <testVectorVector2>
         <element>
           <element greeting="hey"/>
           <element greeting="hi"/>
           <element greeting="good morning"/>
         </element>
         <element>
           <element greeting="hello"/>
           <element greeting="nice weather!"/>
         </element>
       </testVectorVector2>
       <testVector2>
         <element>a</element>
         <element>b</element>
         <element>c</element>
         <element>d</element>
         <element>e</element>
         <element>f</element>
       </testVector2>
     </TestDTO>

    XMLCreator can be easily compiled to an Air app, which will parse your DTOs to XML files and save them on your hard drive.

    Hope I will never see any handwritten and custom parsed XML again!
    You are an ActionScript (not an XML!) developer after all!

    Enjoy!

    References:
    [1]http://en.wikipedia.org/wiki/Data_Transfer_Object
    [2]http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html

     
  • Joony 12:08 am on Thursday, April 29th, 2010 Permalink | Reply
    Tags: , blobs, lava   

    Five minute experiments – Lava 

    I only had a spare five minutes today to mess around in ActionScript today, so I created this:

    You need Flash Player 9 or above installed to view this example.


    It’s nothing new, but I like how easy it is to create effects like this. I’m so lazy!

    package ch.forea.experiments{

      import flash.events.Event;
      import flash.display.Sprite;
      import flash.display.BlendMode;
      import flash.filters.BlurFilter;

      public class Lava extends Sprite{

        private var drops:Array = new Array();
        private var speeds:Array = new Array();
        private var blurs:Array = new Array();

        public function Lava(){
          stage.addEventListener(Event.ENTER_FRAME, checkDrops);
        }

        private function addDrop():void{
          var drop:Sprite = new Sprite();
          drop.blendMode = BlendMode.ADD;
          var blur:uint = Math.random() * 100 + 50;
          var blurFilter:BlurFilter = new BlurFilter(blur, blur, 2);
          drop.filters = [blurFilter];
          blurs[blurs.length] = blurFilter;
          setupDrop(drop);
          drops[drops.length] = drop;
          speeds[speeds.length] = Math.random() * 12 + 3;
          addChildAt(drop, 0);
        }

        private function renewDrop(i:uint):void{
          var drop:Sprite = drops[i] as Sprite;
          drop.graphics.clear();
          var blur:uint = Math.random() * 100 + 50;
          var blurFilter:BlurFilter = blurs[i] as BlurFilter;
          blurFilter.blurX = blurFilter.blurY = blur;
          setupDrop(drop);
          speeds[i] = Math.random() * 12 + 3;
        }

        private function setupDrop(drop:Sprite):void{
          drop.graphics.beginFill(Math.random() * 0xFFFFFF);
          drop.graphics.drawCircle(0, 0, Math.random() * 190 + 10);
          drop.graphics.endFill();
          drop.y = -drop.height;
          drop.x = (Math.random() * stage.stageWidth + drop.width) - drop.width;
        }

        private function checkDrops(e:Event):void{
          for(var i:uint = 0; i < drops.length; i++){
            drops[i].y += speeds[i]
            if(drops[i].y >= stage.stageHeight + drops[i].height)
              renewDrop(i);
          }
          if(drops.length < 25 && Math.random() > .75)
            addDrop();
        }

      }

    }
     
    • Adam 11:26 pm on Monday, May 3rd, 2010 Permalink

      Grooovy!

  • Joony 11:48 pm on Friday, April 23rd, 2010 Permalink | Reply
    Tags:   

    Digital Flip Book 

    I was testing out some strategies for storing some data. Specifically, the lines on a digital whiteboard. While testing I discovered that I could render about 90Kbytes of data a frame if I stored the location of a point in four bytes and recorded the end of the line with another two bytes. I’m storing the bytes in a ByteArray and saving it to a local shared object.

    (points * 4) + 2 = number of bytes used to store line

    This allows for a canvas size of 65534 x 65534.

    The controls are:
    right – advance a frame (a ghost of the previous frame will be displayed
    left – retreat a frame
    delete/backspace – remove a frame
    ctrl/command z or alt z – undo point
    return – play the animation from the start

    You need Flash Player 10 or above installed to view this example.

     
    • Adam 5:03 pm on Monday, April 26th, 2010 Permalink

      Dam you man, get a save feature, I could have sold my creation to Disney for millions, but nooooooo……. You’re to lazy to program a save feature…. sheesh!

    • Joony 8:52 pm on Monday, April 26th, 2010 Permalink

      No, no save feature, just an automatic send to me feature. Hello Disney, hello millions! MWAHAHAHAHAHAHA!!

  • alyoka 4:45 pm on Wednesday, April 14th, 2010 Permalink | Reply
    Tags:   

    Utils: Generic object description 

    When transferring data between different parts of the application we use quite a lot DTOs (for those not aware of the concept I would recommend to start by reading our post about DTOs: http://forea.ch/blog/2008/11/14/back-to-basics-the-data-transfer-object-dto).

    It is often quite useful to see what data is being sent around while the program is running (without having to step through it). What we usually do is insert a couple of traces here and there to have an overview of what is going on.

    In ActionScript objects are traced as [object ObjectClassName] unless you provide a custom toString() method. But how boring would it be to write a specific toString() for each of your DTO’s (and we usually have quite a lot of them). Thankfully, we can use describeType() method to get all the variables and accessors of the object and create a generic toString() method to return the object’s name and all its public properties.

    AbstractDTO.as:

    package ch.forea.dto {
      import flash.utils.describeType;
      import flash.utils.getQualifiedClassName;
      public class AbstractDTO {
        //formats a custom object as YourDtoClassName (param1 = value1, ..., paramN = valueN)
        public function toString() : String {
          var objectString : String = getQualifiedClassName(this) + "(";
          var description:XML = describeType(this);
          var variables : XMLList = description..variable;
          var variablesString : Array = new Array();
          //add all variables
          for each (var child:XML in variables) {
            variablesString.push(child.@name + " = " + (child.@type == "Object" ? formatObject(this[child.@name]) : this[child.@name]));
          }
          //add all accessors
          var accessors:XMLList = description..accessor;
          for each (child in accessors){
            if(child.@access.toString() != "writeonly"){
              variablesString.push(child.@name + " = " + (child.@type == "Object" ? formatObject(this[child.@name]) : this[child.@name]));
            }
          }
          objectString += variablesString.join(", ");
          return objectString + ")";
        }
        //formats an anonymous object as {param1:value1, …, paramN:valueN}
        private function formatObject(object:Object):String{
          var varString:Array = new Array();
          for(var i:String in object){
            varString.push(i + ":" + object[i]);
          }
          return "{" + varString.join(", ") + "}";
        }
      }
    }

    By extending AbstractDTO your DTO will inherit its toString() method and will be traced as:
    YourDtoClassName (param1 = value1, …, paramN = valueN)

    Note, that if a property’s value is an anonymous object, method formatObject will be used to list all its properties. Its value will be added to the output string in the following format: {param1:value1, …, paramN:valueN}.

    Enjoy!

     
    • free game download 6:47 am on Thursday, April 15th, 2010 Permalink

      Nice Information.. Thx for sharing this

      information

    • MarkSpizer 12:38 pm on Sunday, May 2nd, 2010 Permalink

      great post as usual!

  • Joony 11:26 pm on Thursday, April 8th, 2010 Permalink | Reply
    Tags: , AVM2   

    Correction to Error in ActionScript Virtual Machine 2 (AVM2) Overview 

    I just noticed an error while going through the AVM2 instructions. On page 66 the description of greaterequals incorrectly refers to greaterthan under format and forms.

    Format
        greaterthan
    Forms
        greaterthan = 175 (0xaf)

    It should state:

    Format
        greaterequals
    Forms
        greaterequals = 176 (0xb0)

     

    Also Page 92 states:

    Forms
        pushdouble = 46 (0x2f)

    It should state:

    Forms
        pushdouble = 47 (0x2f)

     

    References

    avm2overview.pdf – http://www.adobe.com/devnet/actionscript/articles/avm2overview.pdf
    ActionBlockConstants.h (Tamarin Source) – http://hg.mozilla.org/tamarin-central/file/fbecf6c8a86f/core/ActionBlockConstants.h

     
    • Chris 6:59 am on Wednesday, April 28th, 2010 Permalink

      Thanks a lot, I just came across the same error and your blog came up in a Google search for the correction.

    • Joony 8:54 pm on Wednesday, April 28th, 2010 Permalink

      I’m glad it came in handy to someone. I was wondering how useful it would be as not many people get down and dirty with opcodes. I had to dig through the Tamarin source to find the correct codes. I’ve added a link to the references.

  • Joony 11:14 pm on Wednesday, March 10th, 2010 Permalink | Reply
    Tags: , flash, games   

    Why are Flash games so bad? 

    Every so often I get a little bored and start perusing the Flash games sites. I don’t know why. All the games are the same and have a distinctly home-brewish feel about them. I’m no stranger to home-brew, I’ve been a fan since my Vic20 in the 1980’s, and my interest heightened with my Amiga 1200. My problem though, is that many of these games are commercially made.

    One game that has caught my eye recently is Machinarium. The developers have done a wonderful job, they really have. After playing through the game twice I only have a couple of complaints. One is that you have to move the character close to an object you want to interact with. Why can’t he just walk there for me. That’s what most Graphic Adventures do. It’s only a minor annoyance though. The second complaint is something that all Flash games fall victim to, it’s far too short. It took only a couple of hours to complete. I can see that they already pushed the story as far as it would go, but for €15,12 I was expecting more.

    Twenty years ago you could get a game for around the same price as that of Machinarium and it would take you weeks to complete. For that price you also got a box, manual, disks, and possibly some extras. Sure the graphics were of low resolution, but I would never say they were bad. What they lacked in fidelity, your imagination more than made up for. Playability was what games were about.

    Back then storage was sparse and expensive, hardware wasn’t any cheaper, and games required rewriting in order to play on different systems. Games were squeezed in to 1/100th of the space of modern games, and to get decent performance, developers had top push the hardware to the max, and hardware pushed developers to breaking point. Optimisation was a must.

    Teams of developers laboured arduously for years. At the same time, one man in his bedroom could craft a masterpiece in a matter of months. The gaming industry was booming.

    I mention this because you can easily draw a parallel between those times and developing for the Flash Player today. There are both professional teams and bedroom programmers out there, and there are more games out there now than there even was. The Flash player is limited in its performance, and although bandwidth is increasing daily, downloading 350Mbytes just to play a game online is still out-with our grasp. Flash games have to be small.

    What’s the problem with Flash games?

    My problem really is the lack of recognition for the platform. If Flash was respected in any way as a platform for commercial gaming then we would see a lot more investment by game studios and publishers. There is no reason we can’t make games like the early 1990’s classic Monkey Island. The language and player are more than capable, the hardware is better, we have twenty years of lessons learned, and it’s now cheaper than ever to advertise and distribute games. Just because the games have to be small, doesn’t mean they have to be lacking anything.

    If the platform isn’t the problem, what is?

    he entry requirements are low, there isn’t a financial barrier requiring expensive software to start developing, tutorials and forums are plentiful. This sounds good, but many people barely grasp the basics of the language before not just working professionally, but gaining senior positions. I’ve heard developers spout such rubbish as “this is highly optimised” without even testing it (or even knowing how to test it), and basing their assumption solely on what they think they know. I’ve also worked with a head of development who didn’t know how classes worked. If a developer thinks he’s the best and has nobody to look up to, then all hope is lost for that developer to improve and evolve as a programmer. And if these people are helping other people then what hope does anyone have?

    Who’s to blame for this lack of talent?

    Adobe. Recently, a man who doesn’t even need to say anything to be quoted, Steve Jobs said “Adobe are lazy.” While I believe Adobe are lazy in some respects, I think that Mr Jobs has laziness confused with lack of focus. Adobe are too busy trying to please everybody. For the past few years they’ve been trying really hard not to alienate designers, as they were the ones that first bought in to the idea of Flash. By pandering to the lowest common denominator, Adobe have kept a majority of these non-programmers using ActionScript and prevented the language from maturing and attracting highly skilled Software Engineers from other languages.

    But the buck doesn’t stop at Adobe. Once a game is complete it can be put on any number of Flash game sites (excuse me if I don’t mention them here) with the added allure of instantly earning the ever desirable Mochi-pennies. This ease of publishing promotes a try anything attitude which, unfortunately, is to the detriment of overall quality. It also promotes a revenue hungry clone war, where popular games are cloned to death to try and attract some of the attention and pennies away from the original. Tower Defence is just one such example. We could do without encouragement like this.

    Summary

    The problems with Flash today can be accounted to: the low entry requirements set by Adobe saturating the market with under-qualified developers; over cocky developers making it difficult for employers to cut the muster while performing interviews; and Flash games sites encouraging anyone to upload anything in the search for profit.

    I really think Adobe should just let the non-programmers go. ActionScript is for programmers, and that’s not a bad thing, it would allow the non-programmers to stick to what they’re good at. If such an event was to occur, the quality of developers and what they produce would surely increase.

    I dream a future of high quality Flash titles that kids will be talking about twenty years from now as I talk about games like Monkey Island today.

     
  • Joony 10:11 pm on Wednesday, February 10th, 2010 Permalink | Reply
    Tags: , , cast, conversion, data types, explicit coercion, , top level functions, typecasting   

    Back to Basics: Typecasting 

    Typecasting, also known a Explicit Type Conversion/Coercion, has changed slightly since Actionscript 2.0 but Adobe has kept backwards compatibility, which has led to some misunderstandings and confusion.

    The Actionscript 2.0 way, which is still valid in Actionscript 3.0, of type casting looks like this:

    Class(object)

    Actionscript 3.0 now offers an alternative way to typecast:

    (object as Class)

    Exceptions to the rule

    While the old method still works in Actionscript 3.0 there are a few exceptions. The exceptions are with the following types:

    • Array
    • Boolean
    • Date
    • int
    • Number
    • String
    • uint
    • Vector
    • XML
    • XMLList

    The reason for these exceptions is that there are Top Level Functions of the same names which Adobe has provided for conversion purposes.

    Here are examples of these Top Level Functions and how they affect typecasting:

    Array()

    You need Flash Player 10 or above installed to view this example.

    Result: A new Array has been created and the initial Array now populates the first element of the new one. If the object you pass in to Array() is of type Array then you will receive the following warning at compile time:
    “Warning: Array(x) behaves the same as new Array(x). To cast a value to type Array use the expression x as Array instead of Array(x).”
    Source for test: TopLevelFunctionArrayTest.as

    Boolean()

    You need Flash Player 10 or above installed to view this example.

    Result: Booleans are treated as a Primitive type and the value is compared. The existance of a number > 0 passed in to Boolean() equates to true. Two different types have been compared and match.
    Source for test: TopLevelFunctionBooleanTest.as

    Date()

    You need Flash Player 10 or above installed to view this example.

    Result: Date() will only return a string representation of current date. Beware, passing an argument to Date() will not throw an ArgumentError but you will receive the following warning at compile time:
    “Date(x) behaves the same as new Date().toString(). To cast a value to type Date use “x as Date” instead of Date(x).”
    Source for test: TopLevelFunctionDateTest.as

    int()

    You need Flash Player 10 or above installed to view this example.

    Result: ints are treated as a Primitive type and the value is compared. A floating point number passed in to int() will be truncated at the decimal point. Two different types and values have been compared and match.
    Source for test: TopLevelFunctionIntTest.as

    Number()

    You need Flash Player 10 or above installed to view this example.

    Result: Numbers are treated as a Primitive type and the value is compared. A string containing a number passed in to Number() will be parsed as a Number. Two different types and values have been compared and match.
    Source for test: TopLevelFunctionNumberTest.as

    String()

    You need Flash Player 10 or above installed to view this example.

    Result: Strings are treated as a Primitive type and the value is compared. An objects toString() method returns a string. Two different types have been compared and match.
    Source for test: TopLevelFunctionStringTest.as

    uint()

    You need Flash Player 10 or above installed to view this example.

    Result: uints are treated as a Primitive type and the value is compared. A negative number passed in to uint() will be added to uint.MAX_VALUE (4294967295). Two different types and values have been compared and match.
    Source for test: TopLevelFunctionUintTest.as

    Vector()

    You need Flash Player 10 or above installed to view this example.

    Result: If the argument passed in to Vector() is a Vector of the same type, the argument is returned. This allows the Vector to be typed correctly. However, it will still try and convert other types to Vector.
    Source for test: TopLevelFunctionVectorTest.as

    XML()

    You need Flash Player 10 or above installed to view this example.

    Result: If the argument passed in to XML() is of type XML the argument is returned. This allows the XML to be typed correctly. However, it will still try and convert other types to XML.
    Source for test: TopLevelFunctionXMLTest.as

    XMLList()

    You need Flash Player 10 or above installed to view this example.

    Result: If the argument passed in to XMLList() is of type XMLList the argument is returned. This allows the XMLList to be typed correctly. However, it will still try and convert other types to XMLList.
    Source for test: TopLevelFunctionXMLListTest.as

    Performance

    You need Flash Player 10 or above installed to view this example.

    Result: 45.8ns for the as operator, 12.3ns for Class(object), on my computer. The as operator is over 3.7 times slower. Bear in mind that these are Nanoseconds. An application running at 30fps could typecast using the as operator over 650,000 times per frame.
    Source for test: TypecastingPerformanceTest.as

    As Joa Ebert states on his wiki [1], “This version [Class(object)] is significantly faster than using the as operator.” This is backed up in the results seen above. The reason for this, as Joa puts it is “…[when using Class(object)] Flash Player throws an error if both types do not match and does not perform a conversion to null.” However, as always, it’s not quite as simple as that. Using Top Level/Package Level Functions is slower, as they do have to perform a conversion.

    Casting an object of a different type

    Using the as operator, to quote the LiveDocs [2], “Evaluates whether an expression specified by the first operand is a member of the data type specified by the second operand. If the first operand is a member of the data type, the result is the first operand. Otherwise, the result is the value null.” No error will be thrown during this operation. However, you are most likely to get a Null Object Reference error when trying to access methods or properties of the object which was unsuccessfully typecast.

    Using the Class(object) method of typecasting has the following results:

    Number, int, and uint will call an objects valueOf() method which, by default, will call the objects toString() method which will then be coerced to a numeric type.

    String will call the toString() method directly and use that.

    Boolean is different in that it will return true if the reference is not null, false otherwise.

    For all other reference objects that do not have Top Level/Package Level Functions a Type Coercion error with the thrown.

    Examples and more details on conversions can be found on the Adobe Help site [3].

    Summary

    As you can see, typecasting is a bit of a minefield, especially for developers new to Actionscript.

    I recommend using the as operator unless you specifically want type conversion. This way you preserve some form of continuity in your code by treating every object the same, as Arrays and Dates can only be typecast in this manner, and your intentions are made clear to anyone else who may be working with your code. You will have to watch out for Null Object References though, as the as operator is guaranteed to return null if the object is not a member of the specified data type.

    However, if you’re going for speed, use Class(object) unless a Top Level/Package Level Function exists for that type, with the exception of Vector, XML, and XMLList, but only if you’re absolutely sure of the type as they will still try and convert other objects. Using the numbers from the performance test above, converting your castings from the as operator will not make a significant difference. If you convert 40,000 as operator castings you would reduce the time used from 1.85ms to 1ms. I suggest your time would be better spent elsewhere.

    References

    [1] Casting – ActionScriptWiki

    [2] Operators (ActionScript 3.0) – as

    [3] Adobe ActionScript 3.0 * Type conversions

    For more information on Top Level Functions, check out the docs at:

    http://help.adobe.com/en_US/FlashPlatform/beta/reference/actionscript/3/package.html

     
  • Joony 1:22 am on Saturday, February 6th, 2010 Permalink | Reply
    Tags: , , number, random   

    Random numbers, with the ability to skip a number 

    We recently came across the problem, which we’ve been over many times with people, of having to generate a random number. We have a list of servers . At any point we could be asked to disconnect and reconnect to a random server. Since we don’t want to reconnect to the same server again, we also had to add a number in which to skip.

    The problem most people have with random numbers, without even knowing it, is with even distribution. Let me explain with an example. The most common implementation I’ve seen is as follows:

    Math.round(Math.random() * 10)

    This is supposed to generate a random number between 0 and 10, which of course it does. The misunderstanding in this is that it has a hidden bias away from the 0 and 10. Not very random then! The problem is with the rounding. If the number is between 0 and 0.49 the it will round to 0, but if the number is between 0.5 and 1.49 then it will round to 1. That’s makes 1 twice as likely as 0 to be picked.

    A way to avoid this is to use Math.floor() and add 1 to the highest number you want.

    The following is the method we used, getRandomNumber(), and a method which tests it.

    package ch.forea.spiketest{
      import flash.display.Sprite;
      import flash.text.TextField;
      import flash.utils.setTimeout;
      public class RandomNumberTest extends Sprite{
        private var tf:TextField = new TextField();

        public function RandomNumberTest(){
          tf.text = "RandomNumberTest\n\nRunning test...\n";
          tf.width = 500;
          tf.height = 400;
          addChild(tf);

          setTimeout(runTest, 10);
        }

        private function runTest():void{
          var countl:uint = 0;
          var counth:uint = 0;
          var random:uint;
          var skip:int = 3;
          var low:uint = 0;
          var high:uint = 4;
          var l:uint = 10000000;
          for(var i:uint = 0; i < l; i++){
            random = getRandomNumber(low, high, skip);
            if(random == low) countl++;
            if(random == high) counth++;
            if(random == skip){
              tf.appendText("ERROR: skip hit\n");
              break;
            }
            if(random > high){
              tf.appendText("ERROR: random > high\n");
              break;
            }
          }
          tf.appendText("Results of " + l + " iterations of creating a random number between " + low + " and " + high + (skip != -1 ? " while skipping " + skip : "") + ":\n\tnumber of times the lowest number was hit = " + countl + "\n\tnum\
    ber of times the highest number was hit = "
    + counth + "\n\taverage number of times any number should be hit = " + (l / high+1));
        }

        private function getRandomNumber(low:uint, high:uint, skip:int = -1):uint{
          if(skip >= 0){
            var r:Number = 1;//Math.random();                                                                                                                                                                                                  
            if(r == 1) return high;
            var random:uint = Math.floor(r * (high - low)) + low;
            if(random >= skip) random++;
            return random;
          }
          return Math.floor(Math.random() * (1 + high - low)) + low;
        }
      }
    }

    You need Flash Player 9 or above installed to view this example.


     
  • Joony 12:09 am on Wednesday, February 3rd, 2010 Permalink | Reply
    Tags:   

    Architectural Wonders: PureMVC 

    A brief background

    Recently we’ve been working on a large application that is based on PureMVC. PureMVC being the choice of the company we were working for. We joined in around week three of the project, so the project was well under way and the basic structure had been created. The company had previously used PureMVC with success and were keen to continue using it. Fine with us, we’re not unfamiliar with MVC.

    Three months later, some questions have to be answered.

    The Questions

    The first major framework for Flex was Cairngorm. Since it’s release and further adoption by Adobe, many people have highlighted its major failings. I don’t really want to go in to too much detail but I will recap a few of these.

    1. The use of Global Objects
    2. complexity in having to deal with the Model, View, and Controller classes
    3. Dependency of your application on the framework.

    These are just a few of main problems people have with Cairngorm. I’ve highlighted these three for a reason, buy over time it’s become apparent that Cairngorm is riddled with too many bad decisions and “anti-patterns” to mention.

    So if you’ve been put off by Cairngorm, what are your options? The next biggest contender is PureMVC. It’s been around since 2006, has been ported to over ten languages, and is in use in hundreds of project. Impressive. So let’s see how PureMVC holds up against Cairngorm.

    First of all PureMVC uses the same Global Object structure, the Model, View, and Controller classes are all Global Objects. Not the best start.

    Secondly, in order to address the issue of having to deal with the MVC classes separately, PureMVC hides these classes behind a Facade, which is also a Global Object. In order to access anything you use the “facade” property which you inherit through the Notifier class. It looks a little something like this:

             // Local reference to the Facade Singleton
             protected var facade:IFacade = Facade.getInstance();

    PureMVC Standard source code (http://puremvc.org/pages/docs/AS3/standard/framework_source/)

    Interesting. The facade property is an implementation of IFacade, which would be your specific application’s implementation of Facade, Facade being more of an Abstract implementation. But this property is really just to hide the fact you’re calling the static method getInstance() on the Facade class. On closer inspection, the real horror is revealed.

             /**
             * Constructor.
             *
             * <P>
             * This <code>IFacade</code> implementation is a Singleton,
             * so you should not call the constructor
             * directly, but instead call the static Singleton
             * Factory method <code>Facade.getInstance()</code>
             *
             * @throws Error Error if Singleton instance has already been constructed
             *
             */

            public function Facade( ) {
                if (instance != null) throw Error(SINGLETON_MSG);
                instance = this;
                initializeFacade();    
            }

            /**
             * Facade Singleton Factory method
             *
             * @return the Singleton instance of the Facade
             */

            public static function getInstance():IFacade {
                if (instance == null) instance = new Facade( );
                return instance;
            }

    PureMVC Standard source code (http://puremvc.org/pages/docs/AS3/standard/framework_source/)

    So, the subclass of Facade will call the super class’ constructor and set the instance property, which is global, to this. Making this the most seriously disgusting abuse of an already quite horrible anti-pattern. This may all sound too familiar. This is exactly how the ServiceLocator works in Cairngorm!

    But it doesn’t end there.

    “…[Singleton use] introduces unnecessary limitations in situations where a sole instance of a class is not actually required…” Wikipedia (http://en.wikipedia.org/wiki/Singleton_pattern)

    This is exactly the problem that PureMVC ran in to a while back. What if you want to use PureMVC in several places within your application? Impossible, because, as you can see in the code snippet above, if you try and instantiate the Facade more than once, it will throw an error. Really useful. So how did PureMVC tackle that issue? Well, Instead of realising that there were fundamental flaws in their architecture and re-factoring them out they opted for the quick solution and upgraded the Singletons to, wait for it, Multitons!

              /**
              * Constructor.
              *
              * <P>
              * This <code>IFacade</code> implementation is a Multiton,
              * so you should not call the constructor
              * directly, but instead call the static Factory method,
              * passing the unique key for this instance
              * <code>Facade.getInstance( multitonKey )</code>
              *
              * @throws Error Error if instance for this Multiton key has already been constructed
              *
              */

             public function Facade( key:String ) {
                 if (instanceMap[ key ] != null) throw Error(MULTITON_MSG);
                 initializeNotifier( key );
                 instanceMap[ multitonKey ] = this;
                 initializeFacade();    
             }
             // The Multiton Facade instanceMap.
             protected static var instanceMap : Array = new Array();

    PureMVC Multicore source code (http://puremvc.org/pages/docs/AS3/multicore/framework_source/)

    I’ve never heard of anything so ridiculous! As Wiki puts it, the Singleton patten is designed “…to restrict instantiation of a class to one object.” How do you even come up with an idea like the Multiton?! You’ve got to be really desperate, or really lazy. I’m guessing both.

    This brings around the third issue. PureMVC forces the same type of dependancy of the framework upon your application. Tip: if you have to extend a class from the framework or see an import statement that imports a class from the framework, you’ve got a dependancy.

    Due to this dependancy the developers of PureMVC were obviously in too deep to be able to make the drastic changes needed to implement a decent solution to the Singleton problem without breaking the upgrade possibility of every existing application. Or even worse, I guess, and put existing users off by requiring them to learn a new framework. Don’t get this confused with an excuse, it’s only a reason. There is no excuse for not doing the right thing.

    And I’m not even finished. PureMVC has created its own, inferior, implementation of the EventDispatcher. Why? The official line is “portability,” essentially meaning the framework isn’t even focused on Actionscript. Why favour the few people who will use PureMVC in different languages over the many who will only ever use it in Actionscript?

    I’m not even going to mention how hard it is to Unit Test this type of code. Put it this way, why do we have projects like the following?

    http://code.google.com/p/puremvc-flexunit-testing/

    To summarise, on my three bad points about Cairngorm, PureMVC fails on all three, and then falls deeper in to the hole by implementing an awful “solutions” to make it “easier” to use just to provide the basic functionality people need.

    I see PureMVC and Cairngorm as awful frameworks which are perceived to be good and “best practice.” To me this only encourages bad practice and anti-patterns. The sooner we are rid of them the better.

    So why is PureMVC held in such high regard? I simple don’t know. Maybe some PureMVC fanboys can explain.

    Acknowledgments and References

    http://puremvc.org/
    http://opensource.adobe.com/wiki/display/cairngorm/Cairngorm
    http://en.wikipedia.org/wiki/Singleton_pattern
    http://en.wikipedia.org/wiki/Multiton
    http://en.wikipedia.org/wiki/Model–view–controller

     
  • Joony 9:41 am on Monday, September 21st, 2009 Permalink | Reply
    Tags: Flash on the Beach, FOTB, shenanigans   

    Flash on the Beach ‘09 

    Alyoka and I have made it to Flash on the Beach :)

    Follow our antics at:

    http://twitter.com/Alyoka

    http://twitter.com/Joony

    First off the Keynote, followed by Keith Peters (always good).

    If you see us, be sure to say hello!

     
c
compose new post
j
next post/next comment
k
previous post/previous comment
r
reply
e
edit
o
show/hide comments
t
go to top
l
go to login
h
show/hide help
esc
cancel