
Have you ever accidentally hardcoded information into your program, to later realize it would be easier to not have to compile for small changes?
Storing information in XML allows you an easy way to change parts of your program, without needing to re-compile.
You can store entire levels, character definitions, and directions to artwork from xml.
This enables you to create a fully functioning game or application, and make it easy for yourself or other people to change the content of your program.
This tutorial just shows you how to create an xml file, put information in it, load it using actionscript, and run the program based off the content of the xml.
We will be creating a small “side scrolling” game. It is by no means complete, but should show how you can store game information in XML.
Creating your xml file
The first thing you need to do is create an xml file. If you don’t have a current FlashDevelop Project you are working in, you’ll need to create one.
Next, right click on your ‘src’ folder, and go to ‘Add->New XML File’ and name it ‘data.xml’ and click ‘OK’(you can also create a new text file in explorer, and rename it to .xml).
FlashDevelop sets up a basic xml file:
<!--?xml version="1.0" encoding="utf-8" ?-->Your ‘root node’ has already been created, named ‘data’. You’ll notice that the syntax in xml is very simmilar to html, except that you can declare whatever tags and attributes you want. XML is just a way of organizing your data.
Now we’ll create a couple “basic levels”, and define where some of our art work is located.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | <data> <levels> <level name="Red Island"> <shapes> <shape type="rectangle" x="0" y="0"> <name>space background</name> <width>800</width> <height>600</height> <color>0x000000</color> <is_ground>false</is_ground> </shape> <shape type="circle" x="0" y="0"> <name>Star Outline</name> <radius>610</radius> <color>0xffb400</color> </shape> <shape type="circle" x="0" y="0"> <name>Star</name> <radius>600</radius> <color>0xFF0000</color> </shape> <shape type="circle" x="700" y="20"> <name>tiny star1</name> <radius>2</radius> <color>0xFFFFFF</color> </shape> <shape type="circle" x="720" y="200"> <name>tiny star1</name> <radius>2</radius> <color>0xFFFFFF</color> </shape> <shape type="circle" x="300" y="300"> <name>Moon1</name> <radius>100</radius> <color>0x3388CC</color> </shape> <shape type="circle" x="600" y="400"> <name>Moon2</name> <radius>100</radius> <color>0x3388CC</color> </shape> <shape type="rectangle" x="0" y="550"> <name>ground</name> <width>800</width> <height>50</height> <color>0x006666</color> <is_ground>true</is_ground> </shape> <shape type="rectangle" x="250" y="450"> <name>floating block</name> <width>50</width> <height>50</height> <color>0x006666</color> <is_ground>true</is_ground> </shape> </shapes> <starting_point x="100" y="300"/> </level> </levels> <entities> <entity name="bobby" type="hero"> <filename>lilguy.png</filename> <health>100</health> <speed>10</speed> </entity> </entities> </data> |
Here, I just tried to decide on things from my “game” that I would want to store in xml.
I made an xml tag for “shapes” to go under, and then defined circles and rectangles, based on where I’d want to place them.
These make up an outerspace solar system — a giant red star, a few blue moons close by, and a few stars in the background. I also added two blocks to be used as interactive blocks to stand on.
I also added a “starting position” for out hero to start in our level.
I also created a tag for entities– so we can put enemies, allies, ect in here, but for now I just put the hero player, with a path/ filename to an image I created, and a tag for the health and speed of the character.
To load images externally, they must be in your ‘bin’ folder(or sub-folder) for loading using the ‘Loader’ class, or in your ‘bin’ folder if using an embed tag.
You’ll notice that for some tags I either created a sub tag, or an attribute. It’s really up to your discretion — I could have put filename and speed as attributes on the entity tag, like I did with the name, or I could have made the name attribute a sub-tag/ node.
The only difference is just how you refer to them in your actionscript, as you’ll see in the next part.
Creating Actionscript for loading
Now we need to setup our actionscript to load in the xml, load in any images defined in the xml, and create and setup the level.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | package { import flash.display.Bitmap; import flash.display.Loader; import flash.display.Sprite; import flash.events.Event; import flash.events.KeyboardEvent; import flash.geom.Rectangle; import flash.net.URLLoader; import flash.net.URLRequest; import flash.ui.Keyboard; /** * ... * @author Chris */ public class Main extends Sprite { public var data:XML; public var images:Array; public var blocks:Array; public var loaded_images:int; public var hero:Bitmap; public var hero_speed:Number; public var level_loaded:Boolean; public function Main():void { if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE, init); } private function init(e:Event = null):void { removeEventListener(Event.ADDED_TO_STAGE, init); // entry point images = new Array(); blocks = new Array(); loaded_images = 0; level_loaded = false; hero_speed = 1; var loader:URLLoader = new URLLoader(new URLRequest("data.xml")); loader.addEventListener(Event.COMPLETE, DataLoaded); addEventListener(Event.ENTER_FRAME, RunGame); stage.addEventListener(KeyboardEvent.KEY_DOWN, MoveHero); //loader.load(); } public function DataLoaded(e:Event):void { data = new XML(e.target.data); trace("loaded data"); LoadImages(); //CreateLevel(0); } public function LoadImages():void { //check if all images loaded, and create level if it is if (loaded_images == data.entities.children().length()) { trace("loading complete, images.length = " + images.length); CreateLevel(0); return; } var loader:Loader = new Loader() loader.load(new URLRequest(data.entities.children()[loaded_images].filename)); loader.contentLoaderInfo.addEventListener(Event.COMPLETE, StoreImage); } public function StoreImage(e:Event):void { var bitmap:Bitmap = Bitmap(e.target.content); images.push( { name:data.entities.children()[loaded_images].@name, image:bitmap.bitmapData } ); loaded_images++; LoadImages(); } public function CreateLevel(level:int):void { this.graphics.clear(); for (var i:String in data.levels.children()[level].shapes.children()) { var shape:XML = data.levels.children()[level].shapes.children()[i]; if (shape.@type == "circle") { this.graphics.beginFill(shape.color); this.graphics.drawCircle(shape.@x, shape.@y, shape.radius); this.graphics.endFill(); } else if (shape.@type == "rectangle") { this.graphics.beginFill(shape.color); this.graphics.drawRect(shape.@x, shape.@y, shape.width, shape.height); this.graphics.endFill(); if (shape.is_ground == "true") blocks.push(new Rectangle(shape.@x, shape.@y, shape.width, shape.height)); } } for (var j:String in data.entities.children()) { var entity:XML = data.entities.children()[j]; if (entity.@name == "bobby") { hero_speed = Number(entity.speed); for (var k:String in images) if (images[k].name == "bobby") { hero = new Bitmap(images[k].image); this.addChild(hero); } } } level_loaded = true; hero.x = data.levels.children()[level].starting_point.@x; hero.y = data.levels.children()[level].starting_point.@y; } public function RunGame(e:Event):void { if (!level_loaded) return; var hero_on_ground:Boolean = false; for (var i:String in blocks) { if (hero.y + hero.height > blocks[i].y && hero.x > blocks[i].x && hero.x + hero.width < blocks[i].x + blocks[i].width) { hero.y = blocks[i].y - hero.height+1; hero_on_ground = true; } } if (!hero_on_ground) hero.y+=10; } public function MoveHero(e:KeyboardEvent):void { if (hero == null) return; if (e.keyCode == Keyboard.LEFT) hero.x -= hero_speed; else if(e.keyCode == Keyboard.RIGHT) hero.x += hero_speed; if (hero.y < 0) hero.y = 0; if (hero.x + hero.width > 800) hero.x = 800 - hero.width; } } } |
Line 46–47: The first thing we have to do is setup our ‘loader’ class in the ‘init’ function, to begin loading our xml file, and run the function to then begin loading any images from the xml file.
Line 53: Once the xml is loaded, we call the ‘DataLoaded’ function to convert the loaded xml into our xml object, and call the ‘LoadImages’ function to attempt to load the first (if any) images from xml.
Line 61–74: In the ‘LoadImages’ we first check if their are any images left to load, and if not, we go to loading the rest of the images, and adding them to our ‘images’ array.
Line 82: If we’re finished loading images, then we go to the function ‘CreateLevel’, and load the first defined level.
Line 86: We add graphics for each of our shapes, and add any rectangles that have ‘is_ground’ attribute as true to our ‘blocks’ array, which we can use as a basic “ground”.
Next we search for and create the hero, if he exists.
Line 121: At that point, the “level_loaded” variable is set to true, and the ‘RunGame’ function can now start updating.
Line 125–142: All this function does is move the hero to the ground, and stop him if the bottom left collides with a ‘block’ object.
Line 143: Lastly, I added function to move the hero back and forth, if he exists.
Lastly, I added function to move the hero back and forth, if he exists.
Conclusion
Now you should know how to load level, character, and other data from an xml file, as well as loading an image externally.
Where to go from here?
This is far from a bug-free complete game, and was created to mainly show how to load information from xml.
You can use these techniques in your own applications or games, or you can use this as a building block for a simple side-scroller. Creating proper collision detection for the hero and the blocks, making him jump, ect, shouldn’t take too long from this example.
Download the source Code and please leave me any comments or feedback you have.

Hey Chris, try to replace your code plz. The html entities > & are printed as a text literally, near the RunGame function.
Whoops, darn wordpress!
I pasted it in again, and it seems to have fixed it. Will have to try to figure out a reliable method of pasting in code– < ;(< ) and > ;(>) are automatically replaced sometimes too, but only happens sometimes, which is strange.
Thanks for letting me know!
Yeah, darn wordpress !
Now we can’t see the xml tags and the numbers of the lines on the code too !
Oy, I don’t know why it does that.… but hopefully it’s all good now — unless it changed back the greater than and equal signs! Thanks for seeing that!
Let me know if you want any tutorials on something specific, and I’ll work on getting one up–
Hi Chris,
If there’s anyway you could explain the RunGame
section of the actionscript code I’d really appreciate
it.I just can’t get my head around what causes lilguy
to jump over the block.When I mess with the code it
seems to do the opposite of what I expect!. I’m very new
to this stuff but I keep at it, so I want to understand
things and find out how they function.
Thank You,
Mark Hubrouck
Hi Mark,
the reason why the lil guy “jumps” over the box is bad collision detection
Mainly this line:
if (hero.y + hero.height > blocks[i].y && hero.x > blocks[i].x && hero.x + hero.width < blocks[i].x + blocks[i].width)
which says:
“if(bottom of hero > top of block && the left side of the hero is greater then the left side of the block and hero’s right side is less than the block’s width)”
and this:
if (!hero_on_ground)
hero.y+=10;
so basically when he goes under the block in the air, the bottom of him is below the top of that block, so it assumes he is on the ground and sets him on top of that (so he “jumps” up on there when under it)
A better way might be to use something called “the separating axis theorem” to see if two boxes intersect, Check all four corners of his box, pretend box boxes are circles and check when the distance between them is less than the sum of their radii from both centers, use flash’s built in collision detection(for two movie clips; movie_clip.hitTest(mc2), make the whole world tiled and just find out when he is on a collidable tile, or even box2d.
I’ve mainly just used the simplified version of the separating axis theorem for my stuff
Hi Chris,
Thank you for your speedy and helpful reply.
And thanks for sharing your knowledge with people
like me who have much to learn.
Mark Hubrouck