Get the full commented source code of

HTML5 Suika Watermelon Game

Talking about Actionscript 3 and Flash.

When you are about to design a Flash application using dynamic content, such as an image gallery or a tile based game, XML is one of the best ways to handle external content because it’s very easy to create, understand, read, and update.

AS3 now uses a system called ECMAScript for XML (E4X) that will do most of the dirty job, allowing us to focus on the application we are goingo to write.

From Wikipedia: ECMAScript for XML (E4X) is a programming language extension that adds native XML support to ECMAScript (which includes ActionScript, DMDScript, JavaScript, JScript). The goal is to provide an alternative to DOM interfaces that uses a simpler syntax for accessing XML documents. It also offers a new way of making XML visible. Before the release of E4X, XML was always accessed at an object level. E4X instead treats XML as a primitive (like characters, integers, and booleans). This implies faster access, better support, and acceptance as a building block (data structure) of a program.

So let’s start playing with it, and let me show you the one of the worst XML you can find… a collection of Sokoban levels (guess why?)



  Fly
  Simple Microban-style levels.
  bsimpson_910@hotmail.com
  
    
         ####
         #  #
        ##  ####
      ###.$.$. #
      #  $.$.$ ##
      #  .$@$.  #
      ## $.$.$  #
       # .$.$.###
       ####  ##
          #  #
          ####
    
    
          ####
          #  #
        ###  ####
      ### .$.$. #
      #   $.$.$ ###
      #   .$#$.   #
      ### $.$.$   #
        # .$.$. ###
        ####  ###
           # @#
           ####
    
    
           ####
          ##  ##
          #    ###
      #####$.$.$ ###
      #   $.#.#.$  ##
      #    $.@.$    #
      ##  $.#.#.$   #
       ### $.$.$#####
         ###    #
           ##  ##
            ####
    
  

This is one of the worst XML you can find because it has an unknown number of nodes (I don’t know how many levels has a level collection) and some nodes with multiple attributes.

But you’ll see parsing it with AS3 will be very easy anyway.

Let’s see how to read the xml file:

package {
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.net.URLRequest;
	import flash.net.URLLoader;
	public class sokoxml extends Sprite {
		public function sokoxml() {
			var loader:URLLoader=new URLLoader;
			var req:URLRequest=new URLRequest("sokobanxml.xml");
			loader.addEventListener(Event.COMPLETE,on_xml_completed);
			loader.load(req);
		}
		public function on_xml_completed(event:Event):void {
			var xml_to_parse:XML=new XML(event.target.data);
			trace(xml_to_parse)
		}
	}
}

This would outputs the entire XML file in the same way it was created. Let’ see how does it work:

Lines 8-9: Setting the XML file to load

Line 10: Adding a listener to check if the XML has been completely loaded

Line 11: Loading the file

Line 14: Transforming the file in a XML variable. Not it’s ready to be parsed

The first things we want to look for in an XML file are elements. The elements method lists the elements of an XML object.

package {
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.net.URLRequest;
	import flash.net.URLLoader;
	public class sokoxml extends Sprite {
		public function sokoxml() {
			var loader:URLLoader=new URLLoader  ;
			var req:URLRequest=new URLRequest("sokobanxml.xml");
			loader.addEventListener(Event.COMPLETE,on_xml_completed);
			loader.load(req);
		}
		public function on_xml_completed(event:Event):void {
			var xml_to_parse:XML=new XML(event.target.data);
			for each (var item:XML in xml_to_parse.elements()) {
				trace(item.name()+": "+item+"\n--------------");
			}
		}
	}
}

With the for each loop we can parse all elements even if we do not know how many of them we have in our XML file. The output is pretty similar to the original file because elements method does not care if an element has children.

Title: Fly
--------------
Description: Simple Microban-style levels.
--------------
Email: bsimpson_910@hotmail.com
--------------
LevelCollection: 
  
    ####
    #  #
    ##  ####
    ###.$.$. #
    #  $.$.$ ##
    #  .$@$.  #
    ## $.$.$  #
    # .$.$.###
    ####  ##
    #  #
    ####
  
  
    ####
    #  #
    ###  ####
    ### .$.$. #
    #   $.$.$ ###
    #   .$#$.   #
    ### $.$.$   #
    # .$.$. ###
    ####  ###
    # @#
    ####
  
  
    ####
    ##  ##
    #    ###
    #####$.$.$ ###
    #   $.#.#.$  ##
    #    $.@.$    #
    ##  $.#.#.$   #
    ### $.$.$#####
    ###    #
    ##  ##
    ####
  

--------------

So the first thing to do is to create a recursive function, because we don’t know if a child of an element has its own children, that can have children, and so on. That’s why I am approaching this problem with recursive functions.

package {
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.net.URLRequest;
	import flash.net.URLLoader;
	public class sokoxml extends Sprite {
		public function sokoxml() {
			var loader:URLLoader=new URLLoader  ;
			var req:URLRequest=new URLRequest("sokobanxml.xml");
			loader.addEventListener(Event.COMPLETE,on_xml_completed);
			loader.load(req);
		}
		public function on_xml_completed(event:Event):void {
			var xml_to_parse:XML=new XML(event.target.data);
			for each (var item:XML in xml_to_parse.elements()) {
				recursive(item);
			}
		}
		public function recursive(xml:XML) {
			trace("NAME: "+xml.name());
			trace("VALUE: "+xml.children());
			trace("-----------------");
		}
	}
}

As you can see, the result does not change…

NAME: Title
VALUE: Fly
-----------------
NAME: Description
VALUE: Simple Microban-style levels.
-----------------
NAME: Email
VALUE: bsimpson_910@hotmail.com
-----------------
NAME: LevelCollection
VALUE: 
  ####
  #  #
  ##  ####
  ###.$.$. #
  #  $.$.$ ##
  #  .$@$.  #
  ## $.$.$  #
  # .$.$.###
  ####  ##
  #  #
  ####


  ####
  #  #
  ###  ####
  ### .$.$. #
  #   $.$.$ ###
  #   .$#$.   #
  ### $.$.$   #
  # .$.$. ###
  ####  ###
  # @#
  ####


  ####
  ##  ##
  #    ###
  #####$.$.$ ###
  #   $.#.#.$  ##
  #    $.@.$    #
  ##  $.#.#.$   #
  ### $.$.$#####
  ###    #
  ##  ##
  ####

-----------------

Now it’s time to scan each element and see if it has children. The children method lists the children of the XML object in the sequence in which they appear. So, now for each element I am scanning for children, and for each child (if any), for children of that child, and so on.

package {
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.net.URLRequest;
	import flash.net.URLLoader;
	public class sokoxml extends Sprite {
		public function sokoxml() {
			var loader:URLLoader=new URLLoader  ;
			var req:URLRequest=new URLRequest("sokobanxml.xml");
			loader.addEventListener(Event.COMPLETE,on_xml_completed);
			loader.load(req);
		}
		public function on_xml_completed(event:Event):void {
			var xml_to_parse:XML=new XML(event.target.data);
			for each (var item:XML in xml_to_parse.elements()) {
				recursive(item);
			}
		}
		public function recursive(xml:XML) {
			trace("NAME: "+xml.name());
			if (xml.children()==xml) {
				trace("VALUE: "+xml.children());
				trace("-----------------");
			} else {
				trace("This node has children:");
				for each (var item:XML in xml.children()) {
					recursive(item);
				}
			}
		}
	}
}

Now the XML has been completely parsed, I can see if a node has children and list them properly

NAME: Title
VALUE: Fly
-----------------
NAME: Description
VALUE: Simple Microban-style levels.
-----------------
NAME: Email
VALUE: bsimpson_910@hotmail.com
-----------------
NAME: LevelCollection
This node has children:
NAME: Level
This node has children:
NAME: L
VALUE: ####
-----------------
NAME: L
VALUE: #  #
-----------------
NAME: L
VALUE: ##  ####
-----------------
NAME: L
VALUE: ###.$.$. #
-----------------
NAME: L
VALUE: #  $.$.$ ##
-----------------
NAME: L
VALUE: #  .$@$.  #
-----------------
NAME: L
VALUE: ## $.$.$  #
-----------------
NAME: L
VALUE: # .$.$.###
-----------------
NAME: L
VALUE: ####  ##
-----------------
NAME: L
VALUE: #  #
-----------------
NAME: L
VALUE: ####
-----------------
NAME: Level
This node has children:
NAME: L
VALUE: ####
-----------------
NAME: L
VALUE: #  #
-----------------
NAME: L
VALUE: ###  ####
-----------------
NAME: L
VALUE: ### .$.$. #
-----------------
NAME: L
VALUE: #   $.$.$ ###
-----------------
NAME: L
VALUE: #   .$#$.   #
-----------------
NAME: L
VALUE: ### $.$.$   #
-----------------
NAME: L
VALUE: # .$.$. ###
-----------------
NAME: L
VALUE: ####  ###
-----------------
NAME: L
VALUE: # @#
-----------------
NAME: L
VALUE: ####
-----------------
NAME: Level
This node has children:
NAME: L
VALUE: ####
-----------------
NAME: L
VALUE: ##  ##
-----------------
NAME: L
VALUE: #    ###
-----------------
NAME: L
VALUE: #####$.$.$ ###
-----------------
NAME: L
VALUE: #   $.#.#.$  ##
-----------------
NAME: L
VALUE: #    $.@.$    #
-----------------
NAME: L
VALUE: ##  $.#.#.$   #
-----------------
NAME: L
VALUE: ### $.$.$#####
-----------------
NAME: L
VALUE: ###    #
-----------------
NAME: L
VALUE: ##  ##
-----------------
NAME: L
VALUE: ####
-----------------

The last thing I have to do is checking for attributes. An element can have one or more attributes, or can have no attributes. Also, I don’t know their names and values. That’s when attribute method comes and saves me. attribute returns a list of attribute values for the given XML object.

package {
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.net.URLRequest;
	import flash.net.URLLoader;
	public class sokoxml extends Sprite {
		public function sokoxml() {
			var loader:URLLoader=new URLLoader  ;
			var req:URLRequest=new URLRequest("sokobanxml.xml");
			loader.addEventListener(Event.COMPLETE,on_xml_completed);
			loader.load(req);
		}
		public function on_xml_completed(event:Event):void {
			var xml_to_parse:XML=new XML(event.target.data);
			for each (var item:XML in xml_to_parse.elements()) {
				recursive(item);
			}
		}
		public function recursive(xml:XML) {
			trace("NAME: "+xml.name());
			for each (var att:XML in xml.attributes()) {
				trace("Attribute: "+att.name()+" = "+att);
			}
			if (xml.children()==xml) {
				trace("VALUE: "+xml.children());
				trace("-----------------");
			} else {
				trace("This node has children:");
				for each (var item:XML in xml.children()) {
					recursive(item);
				}
			}
		}
	}
}

And finally the XML has been fully parsed, attributes included

NAME: Title
VALUE: Fly
-----------------
NAME: Description
VALUE: Simple Microban-style levels.
-----------------
NAME: Email
VALUE: bsimpson_910@hotmail.com
-----------------
NAME: LevelCollection
Attribute: Copyright = Tim LeFevre
Attribute: MaxWidth = 15
Attribute: MaxHeight = 11
This node has children:
NAME: Level
Attribute: Id = The Fly_1
Attribute: Width = 11
Attribute: Height = 11
This node has children:
NAME: L
VALUE: ####
-----------------
NAME: L
VALUE: #  #
-----------------
NAME: L
VALUE: ##  ####
-----------------
NAME: L
VALUE: ###.$.$. #
-----------------
NAME: L
VALUE: #  $.$.$ ##
-----------------
NAME: L
VALUE: #  .$@$.  #
-----------------
NAME: L
VALUE: ## $.$.$  #
-----------------
NAME: L
VALUE: # .$.$.###
-----------------
NAME: L
VALUE: ####  ##
-----------------
NAME: L
VALUE: #  #
-----------------
NAME: L
VALUE: ####
-----------------
NAME: Level
Attribute: Id = The Fly_2
Attribute: Width = 13
Attribute: Height = 11
This node has children:
NAME: L
VALUE: ####
-----------------
NAME: L
VALUE: #  #
-----------------
NAME: L
VALUE: ###  ####
-----------------
NAME: L
VALUE: ### .$.$. #
-----------------
NAME: L
VALUE: #   $.$.$ ###
-----------------
NAME: L
VALUE: #   .$#$.   #
-----------------
NAME: L
VALUE: ### $.$.$   #
-----------------
NAME: L
VALUE: # .$.$. ###
-----------------
NAME: L
VALUE: ####  ###
-----------------
NAME: L
VALUE: # @#
-----------------
NAME: L
VALUE: ####
-----------------
NAME: Level
Attribute: Id = The Fly_3
Attribute: Width = 15
Attribute: Height = 11
Attribute: Copyright = 1106 1087 Jordi Doménech
This node has children:
NAME: L
VALUE: ####
-----------------
NAME: L
VALUE: ##  ##
-----------------
NAME: L
VALUE: #    ###
-----------------
NAME: L
VALUE: #####$.$.$ ###
-----------------
NAME: L
VALUE: #   $.#.#.$  ##
-----------------
NAME: L
VALUE: #    $.@.$    #
-----------------
NAME: L
VALUE: ##  $.#.#.$   #
-----------------
NAME: L
VALUE: ### $.$.$#####
-----------------
NAME: L
VALUE: ###    #
-----------------
NAME: L
VALUE: ##  ##
-----------------
NAME: L
VALUE: ####
-----------------

This was the hardest situation, when you don’t exactly know the structure of your XML tree.

But a good PROgrammer always knows the structure of the data he’s playing with, so next time we’ll see how to parse this sokoban level in order to draw it on the screen.

Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.