这篇文章主要是讲解如何基于AS3来制作一个区块游戏,但仍然保持OOP的结构。
这篇文章的代码能够被诸如FlexBuilder,FlashDevilop这里的编译器解释,当然Flash IDE也可以,但是要在主场景上指明main类。
该应用程序需要一个XML文件存储地图数据,它将会被转换为实际地图显示在屏幕上。这里面是没有什么交互的,不过是区块的放置位置和管理。
程序需要X类,每个来都负责不同的功能。
1、main类:管理所有的类和所创建的实例。
2、XmlLoader:载入一个xml文件并保存他的数据。
3、Parser:解析xml到一个二维的数组当中。
4、Screen:接收parser所创建的数字来构造一个区块的矩阵。
5、Tile:单个区块,保存类型x位置和y位置。
在最后我将会给出main文件:
第一个类:XmlLoader:
package tools { import flash.events.EventDispatcher; import flash.net.URLRequest; import flash.net.URLLoader; import flash.events.Event; public class XmlLoader extends EventDispatcher{ private var _loader:URLLoader; private var _xml:XML; public function XmlLoader(path:String){ _loader = new URLLoader(); try{ _loader.load(new URLRequest(path)); }catch(e:Error){ trace("error in loading the XML file") } _loader.addEventListener(Event.COMPLETE,onLoadXml); } private function onLoadXml(event:Event):void{ //trace("xml loaded") _xml = XML(URLLoader(event.target).data) dispatchEvent(new Event(Event.COMPLETE)); } public function get xml():XML{ return _xml; } } } |
这个类接收XML文件的路径,尝试载入它。xml被载入以后,类将会dispatch一个事件,以便创建XmlLoader实例的类能够知道载入已经完成了,我们可以继续了。(这是一个非即时的操作,所有我们需要一个事件机制)。
请注意:有一个事件监听来监听载入的操作,还有一个事件的派遣-main 来接收该事件。第一个市内置的,第二个是同其他的类来连接。载入了xml数据以后,XmlLoader 的实例会保存该数据然后通过其他的类中的一个指定的getter函数来获得它。另一个应该注意到的是try & catch
来处理一些特定的错误事件,这样可以防止一个错误信息在运行中发送给用户。
第二个类:parser
解析的工作是非常的简单的,-获得一个xml对象,然后分割成行,每一行对应一个数字。在完成了划分以后,这个类的一个实例会保存数组中的行以便其他的类能够读取它。这也是由一个getter函数来完成的。_rows数组是一个二维数组。根据xml文件,其中的每一个单元都被描述成一行,每行都有若干的数字。
接收xml文件的类的结构如下所示:
package tools { public class Parser{ private var _xml:XML; private var _rows:Array; public function Parser(xml:XML){ _xml = xml; _rows = new Array(); getRows(); } private function getRows():void{ // get all rows var rows:XMLList = _xml.screen.children(); var singleRow:Array; var rowString:String = rows[i]; for(var i:uint=0;i<rows.length();i++){ rowString= rows[i]; // split numbers in string to cells in singleRow array singleRow = rowString.split(""); //save singleRow in _rows array; _rows.push(singleRow); } } //return an arra of all rows (every row is an array of numbers public function get rows():Array{ return _rows; } } } |
为了能让该工作完成,xml文件的结构应该是这样的:
<?xml version='1.0' encoding='UTF8'?> <data> <screen id="" title=""> <row>111111111111111111111111111111</row> <row>100000000000000000000000000001</row> <row>101000000000000000003300000001</row> <row>101000000000000000000000000001</row> <row>101111110000001111000000000001</row> <row>100000000000004400000000000001</row> <row>100000000000000000000111510001</row> <row>100000000000000000000000000001</row> <row>111111111111111111111111111111</row> </screen> </data> |
如果你是其他的结构需要改变一下parser。
Parser和XmlLoader都在一个名为tools的包中。
第三个类:一个视觉上的Screen:
Screen类的实例接收到数组中的数据(Parser类中所解析成的样子)然后根据数组构建一个区块的矩阵。它需要一个两层的for循环。第一层循环遍历所有的行。内部的循环来遍历行里面的所有的数字。内部的for循环每执行一次都创建一个区块,然后将他放到一个数组中(这样做可以让我们以后访问到所有的区块)。
这个类和Tile类都在一个名为"visual"的包中:
package visual { import visual.Tile; import flash.display.Sprite; public class Screen extends Sprite{ private var _screenArray:Array; private var _tiles:Array; public function Screen(screenArray:Array){ _screenArray = screenArray; _tiles = new Array(); var tile:Tile; var row:Array; // create matrix for(var i:uint=0;i<_screenArray.length;i++){ row = _screenArray[i] as Array; for(var j:uint=0;j<row.length;j++){ // create a new tile and push it to _tiles tile = new Tile(Number(row[j]),j,i) addChild(tile) _tiles.push(tile); } } } //let other classes get the tiles array. public function get allTiles():Array{ return _tiles; } } } |
第四个类:Tile:
最后的visual类是Tile类,它提供单个的区块,具有3个属性:
Type:(代码在XML来描述这一区块)
locationX-描述他在矩阵中的水平位置-数字的位置而不是像素的。
locationY-描述他在矩阵中的垂直的位置。
三个属性都是getter函数。外部的对象可以"ask"每一个区块的属性。我决定使用颜色来区分区块类型的不同。
以下是Tile类的代码:
package visual{ import flash.display.Sprite; public class Tile extends Sprite{ private var _type:uint; private var _locationX:uint; private var _locationY:uint; // colors of tiles static private var TILE_TYPES:Array = [0xDDDDDD, 0xFF00AA, 0xCC00CC, 0xCCCC00, 0x3300FF]; private const TILE_SIZE:uint = 10; public function Tile(type:uint,locationX:uint,locationY:uint){ // get parameters _type = type; _locationX = locationX; _locationY = locationY; //draw a square graphics.lineStyle(1,0x000000,0.2); // different color by type parameter graphics.beginFill( TILE_TYPES[_type],1); graphics.drawRect(0,0,TILE_SIZE,TILE_SIZE); graphics.endFill(); x=TILE_SIZE*_locationX; y=TILE_SIZE*_locationY; } public function get type():uint{ return _type; } public function get locationX():uint{ return _locationX; } public function get locationY():uint{ return _locationY; } } } |
main 类:
最后,我们让所有的东西都运行起来:
package { import flash.display.Sprite; import tools.XmlLoader; import flash.events.Event; import tools.Parser; import visual.Screen public class TileGame extends Sprite{ private var _xmlLoader:XmlLoader; private var _xmlData:XML; private var _screenParser:Parser; private var _screenArray:Array; private var _screen:Screen; public function TileGame(){ var url:String = "http://www.avgil.com/as3/tilegame/screen1.xml"; try{ _xmlLoader = new XmlLoader(url); } catch(e:Error){ trace("couldn't load XML file") } // wait till the XmlLoader will finish loading the data _xmlLoader.addEventListener(Event.COMPLETE,onXmlReady); } private function onXmlReady(event:Event):void{ //recieve the XML data from the event _xmlData = XmlLoader(event.target).xml as XML; //parse and build a screen from parsed data _screenParser = new Parser(_xmlData); _screenArray = _screenParser.rows; _screen = new Screen(_screenArray); _screen.x = 50; _screen.y = 50; addChild(_screen); } } } |
需要注意的是在创建了XmlLoader以后,需要等到XmlLoader说"OK-done"才能做起他的事情。