-
-
Save activeknowledge/3767875 to your computer and use it in GitHub Desktop.
TMX Loader Starling Extension
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (C) 2012 Jean-Philippe Auclair | |
* Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php | |
* Base64 library for ActionScript 3.0. | |
* By: Jean-Philippe Auclair : http://jpauclair.net | |
* Based on article: http://jpauclair.net/2010/01/09/base64-optimized-as3-lib/ | |
* Benchmark: | |
* This version: encode: 260ms decode: 255ms | |
* Blog version: encode: 322ms decode: 694ms | |
* as3Crypto encode: 6728ms decode: 4098ms | |
* | |
* Encode: com.sociodox.utils.Base64 is 25.8x faster than as3Crypto Base64 | |
* Decode: com.sociodox.utils.Base64 is 16x faster than as3Crypto Base64 | |
* | |
* Optimize & Profile any Flash content with TheMiner ( http://www.sociodox.com/theminer ) | |
*/ | |
package | |
{ | |
import flash.utils.ByteArray; | |
public class Base64 | |
{ | |
private static const _encodeChars:Vector.<int> = InitEncoreChar(); | |
private static const _decodeChars:Vector.<int> = InitDecodeChar(); | |
public static function encode(data:ByteArray):String | |
{ | |
var out:ByteArray = new ByteArray(); | |
//Presetting the length keep the memory smaller and optimize speed since there is no "grow" needed | |
out.length = (2 + data.length - ((data.length + 2) % 3)) * 4 / 3; //Preset length //1.6 to 1.5 ms | |
var i:int = 0; | |
var r:int = data.length % 3; | |
var len:int = data.length - r; | |
var c:uint; //read (3) character AND write (4) characters | |
var outPos:int = 0; | |
while (i < len) | |
{ | |
//Read 3 Characters (8bit * 3 = 24 bits) | |
c = data[int(i++)] << 16 | data[int(i++)] << 8 | data[int(i++)]; | |
out[int(outPos++)] = _encodeChars[int(c >>> 18)]; | |
out[int(outPos++)] = _encodeChars[int(c >>> 12 & 0x3f)]; | |
out[int(outPos++)] = _encodeChars[int(c >>> 6 & 0x3f)]; | |
out[int(outPos++)] = _encodeChars[int(c & 0x3f)]; | |
} | |
if (r == 1) //Need two "=" padding | |
{ | |
//Read one char, write two chars, write padding | |
c = data[int(i)]; | |
out[int(outPos++)] = _encodeChars[int(c >>> 2)]; | |
out[int(outPos++)] = _encodeChars[int((c & 0x03) << 4)]; | |
out[int(outPos++)] = 61; | |
out[int(outPos++)] = 61; | |
} | |
else if (r == 2) //Need one "=" padding | |
{ | |
c = data[int(i++)] << 8 | data[int(i)]; | |
out[int(outPos++)] = _encodeChars[int(c >>> 10)]; | |
out[int(outPos++)] = _encodeChars[int(c >>> 4 & 0x3f)]; | |
out[int(outPos++)] = _encodeChars[int((c & 0x0f) << 2)]; | |
out[int(outPos++)] = 61; | |
} | |
return out.readUTFBytes(out.length); | |
} | |
public static function decode(str:String):ByteArray | |
{ | |
var c1:int; | |
var c2:int; | |
var c3:int; | |
var c4:int; | |
var i:int = 0; | |
var len:int = str.length; | |
var byteString:ByteArray = new ByteArray(); | |
byteString.writeUTFBytes(str); | |
var outPos:int = 0; | |
while (i < len) | |
{ | |
//c1 | |
c1 = _decodeChars[int(byteString[i++])]; | |
if (c1 == -1) | |
break; | |
//c2 | |
c2 = _decodeChars[int(byteString[i++])]; | |
if (c2 == -1) | |
break; | |
byteString[int(outPos++)] = (c1 << 2) | ((c2 & 0x30) >> 4); | |
//c3 | |
c3 = byteString[int(i++)]; | |
if (c3 == 61) | |
{ | |
byteString.length = outPos | |
return byteString; | |
} | |
c3 = _decodeChars[int(c3)]; | |
if (c3 == -1) | |
break; | |
byteString[int(outPos++)] = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2); | |
//c4 | |
c4 = byteString[int(i++)]; | |
if (c4 == 61) | |
{ | |
byteString.length = outPos | |
return byteString; | |
} | |
c4 = _decodeChars[int(c4)]; | |
if (c4 == -1) | |
break; | |
byteString[int(outPos++)] = ((c3 & 0x03) << 6) | c4; | |
} | |
byteString.length = outPos | |
return byteString; | |
} | |
public static function InitEncoreChar():Vector.<int> | |
{ | |
var encodeChars:Vector.<int> = new Vector.<int>(64, true); | |
// We could push the number directly | |
// but I think it's nice to see the characters (with no overhead on encode/decode) | |
var chars:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |
for (var i:int = 0; i < 64; i++) | |
{ | |
encodeChars[i] = chars.charCodeAt(i); | |
} | |
return encodeChars; | |
} | |
public static function InitDecodeChar():Vector.<int> | |
{ | |
var decodeChars:Vector.<int> = new <int>[ | |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, | |
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, | |
-1, 0, 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, -1, -1, -1, -1, -1, | |
-1, 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, -1, -1, -1, -1, -1, | |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]; | |
return decodeChars; | |
} | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package | |
{ | |
import starling.display.Sprite; | |
/** | |
* @author shaun.mitchell | |
*/ | |
public class TMXLayer extends Sprite | |
{ | |
private var _layerData:Array = new Array(); | |
private var _layerHolder:Sprite = new Sprite; | |
public function TMXLayer(data:Array):void | |
{ | |
_layerData = data; | |
} | |
public function getData():Array | |
{ | |
return _layerData; | |
} | |
public function getHolder():Sprite | |
{ | |
return _layerHolder; | |
} | |
public function drawLayer():void | |
{ | |
addChild(_layerHolder); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package | |
{ | |
import starling.display.Image; | |
import starling.display.Sprite; | |
import starling.events.Event; | |
import flash.display.Bitmap; | |
import flash.events.Event; | |
import flash.net.URLLoader; | |
import flash.net.URLRequest; | |
import flash.utils.ByteArray; | |
/** | |
* @author shaun.mitchell | |
*/ | |
public class TMXTileMap extends Sprite | |
{ | |
// The TMX file to load | |
private var _fileName:String; | |
private var _loader:URLLoader; | |
private var _mapLoaded:Boolean; | |
// XML of TMX file | |
private var _TMX:XML; | |
// Layers and tilesheet holders | |
private var _layers:Vector.<TMXLayer>; | |
private var _tilesheets:Vector.<TMXTileSheet>; | |
// variables pertaining to map description | |
private var _numLayers:uint; | |
private var _numTilesets:uint; | |
private var _tilelistCount:uint; | |
private var _mapWidth:uint; | |
private var _tileHeight:uint; | |
private var _tileWidth:uint; | |
// used to get the correct tile from various tilesheets | |
private var _gidLookup:Vector.<uint>; | |
private var _embedTilesets:Vector.<Bitmap>; | |
public function TMXTileMap():void | |
{ | |
_mapLoaded = false; | |
_fileName = ""; | |
_loader = new URLLoader(); | |
_numLayers = 0; | |
_numTilesets = 0; | |
_tilelistCount = 0; | |
_mapWidth = 0; | |
_tileHeight = 0; | |
_tileWidth = 0; | |
_layers = new Vector.<TMXLayer>(); | |
_tilesheets = new Vector.<TMXTileSheet>(); | |
_gidLookup = new Vector.<uint>(); | |
} | |
public function load(file:String):void | |
{ | |
_fileName = file; | |
trace(_fileName); | |
_loader.addEventListener(flash.events.Event.COMPLETE, loadTilesets); | |
_loader.load(new URLRequest(_fileName)); | |
} | |
public function loadFromEmbed(tmx:XML, tilesets:Vector.<Bitmap>):void | |
{ | |
_TMX = tmx; | |
_embedTilesets = tilesets; | |
loadEmbedTilesets(); | |
} | |
// Getters ------------------------------------------ | |
public function layers():Vector.<TMXLayer> | |
{ | |
return _layers; | |
} | |
public function tilesheets():Vector.<TMXTileSheet> | |
{ | |
return _tilesheets; | |
} | |
public function numLayers():uint | |
{ | |
return _numLayers; | |
} | |
public function numTilesets():uint | |
{ | |
return _numTilesets; | |
} | |
public function mapWidth():uint | |
{ | |
return _mapWidth; | |
} | |
public function tileHeight():uint | |
{ | |
return _tileHeight; | |
} | |
public function tileWidth():uint | |
{ | |
return _tileWidth; | |
} | |
// End getters -------------------------------------- | |
// get the number of tilsets from the TMX XML | |
private function getNumTilesets():uint | |
{ | |
if (_mapLoaded) | |
{ | |
var count:uint = 0; | |
for (var i:int = 0; i < _TMX.children().length(); i++) | |
{ | |
if (_TMX.tileset[i] != null) | |
{ | |
count++; | |
} | |
} | |
trace(count); | |
return count; | |
} | |
return 0; | |
} | |
// get the number of layers from the TMX XML | |
private function getNumLayers():uint | |
{ | |
if (_mapLoaded) | |
{ | |
var count:uint = 0; | |
for (var i:int = 0; i < _TMX.children().length(); i++) | |
{ | |
if (_TMX.layer[i] != null) | |
{ | |
count++; | |
} | |
} | |
trace(count); | |
return count; | |
} | |
return 0; | |
} | |
private function loadTilesets(event:flash.events.Event):void | |
{ | |
trace("loading tilesets from file"); | |
_mapLoaded = true; | |
_TMX = new XML(_loader.data); | |
if (_TMX) | |
{ | |
_mapWidth = _TMX.@width; | |
_tileHeight = _TMX.@tileheight; | |
_tileWidth = _TMX.@tilewidth; | |
trace("map width" + _mapWidth); | |
_numLayers = getNumLayers(); | |
_numTilesets = getNumTilesets(); | |
// _TMX.properties.property[1].@value; | |
var tileSheet:TMXTileSheet = new TMXTileSheet(); | |
tileSheet.loadTileSheet(_TMX.tileset[_tilelistCount].@name, _TMX.tileset[_tilelistCount].image.@source, _TMX.tileset[_tilelistCount].@tilewidth, _TMX.tileset[_tilelistCount].@tileheight, _TMX.tileset[_tilelistCount].@firstgid - 1); | |
tileSheet.addEventListener(starling.events.Event.COMPLETE, loadRemainingTilesets); | |
_tilesheets.push(tileSheet); | |
_gidLookup.push(_TMX.tileset[_tilelistCount].@firstgid); | |
} | |
} | |
private function loadEmbedTilesets():void | |
{ | |
trace("loading embedded tilesets"); | |
_mapLoaded = true; | |
if (_TMX) | |
{ | |
_mapWidth = _TMX.@width; | |
_tileHeight = _TMX.@tileheight; | |
_tileWidth = _TMX.@tilewidth; | |
trace("map width" + _mapWidth); | |
_numLayers = getNumLayers(); | |
_numTilesets = getNumTilesets(); | |
trace(_numTilesets); | |
// _TMX.properties.property[1].@value; | |
for (var i:int = 0; i < _numTilesets; i++) | |
{ | |
var tileSheet:TMXTileSheet = new TMXTileSheet(); | |
trace(_TMX.tileset[i].@name, _embedTilesets[i], _TMX.tileset[i].@tilewidth, _TMX.tileset[i].@tileheight, _TMX.tileset[i].@firstgid - 1); | |
tileSheet.loadEmbedTileSheet(_TMX.tileset[i].@name, _embedTilesets[i], _TMX.tileset[i].@tilewidth, _TMX.tileset[i].@tileheight, _TMX.tileset[i].@firstgid - 1); | |
_tilesheets.push(tileSheet); | |
_gidLookup.push(_TMX.tileset[i].@firstgid); | |
} | |
loadMapData(); | |
} | |
} | |
private function loadRemainingTilesets(event:starling.events.Event):void | |
{ | |
event.target.removeEventListener(starling.events.Event.COMPLETE, loadRemainingTilesets); | |
_tilelistCount++; | |
if (_tilelistCount >= _numTilesets) | |
{ | |
trace("done loading tilelists"); | |
loadMapData(); | |
} | |
else | |
{ | |
trace(_TMX.tileset[_tilelistCount].@name); | |
var tileSheet:TMXTileSheet = new TMXTileSheet(); | |
tileSheet.loadTileSheet(_TMX.tileset[_tilelistCount].@name, _TMX.tileset[_tilelistCount].image.@source, _TMX.tileset[_tilelistCount].@tilewidth, _TMX.tileset[_tilelistCount].@tileheight, _TMX.tileset[_tilelistCount].@firstgid - 1); | |
tileSheet.addEventListener(starling.events.Event.COMPLETE, loadRemainingTilesets); | |
_gidLookup.push(_TMX.tileset[_tilelistCount].@firstgid); | |
_tilesheets.push(tileSheet); | |
} | |
} | |
private function loadMapData():void | |
{ | |
if (_mapLoaded) | |
{ | |
for (var i:int = 0; i < _numLayers; i++) | |
{ | |
trace("loading map data"); | |
var ba:ByteArray = Base64.decode(_TMX.layer[i].data); | |
ba.uncompress(); | |
var data:Array = new Array(); | |
for (var j:int = 0; j < ba.length; j += 4) | |
{ | |
// Get the grid ID | |
var a:int = ba[j]; | |
var b:int = ba[j + 1]; | |
var c:int = ba[j + 2]; | |
var d:int = ba[j + 3]; | |
var gid:int = a | b << 8 | c << 16 | d << 24; | |
data.push(gid); | |
} | |
var tmxLayer:TMXLayer = new TMXLayer(data); | |
_layers.push(tmxLayer); | |
} | |
drawLayers(); | |
} | |
} | |
// draw the layers into a holder contained in a TMXLayer object | |
private function drawLayers():void | |
{ | |
trace("drawing layers"); | |
for (var i:int = 0; i < _numLayers; i++) | |
{ | |
trace("drawing layers"); | |
var row:int = 0; | |
var col:int = 0; | |
for (var j:int = 0; j < _layers[i].getData().length; j++) | |
{ | |
if (col > (_mapWidth - 1) * _tileWidth) | |
{ | |
col = 0; | |
row += _tileHeight; | |
} | |
if (_layers[i].getData()[j] != 0) | |
{ | |
var img:Image = new Image(_tilesheets[findTileSheet(_layers[i].getData()[j])].textureAtlas.getTexture(String(_layers[i].getData()[j]))); | |
img.x = col; | |
img.y = row; | |
_layers[i].getHolder().addChild(img); | |
} | |
col += _tileWidth; | |
} | |
} | |
// notify that the load is complete | |
dispatchEvent(new starling.events.Event(starling.events.Event.COMPLETE)); | |
} | |
private function findTileSheet(id:uint):int | |
{ | |
var value:int = 0; | |
var theOne:int; | |
for (var i:int = 0; i < _tilesheets.length; i++) | |
{ | |
if (_tilesheets[i].textureAtlas.getTexture(String(id)) != null) | |
{ | |
theOne = i; | |
} | |
else | |
{ | |
value = i; | |
} | |
} | |
return theOne; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package | |
{ | |
import starling.display.Sprite; | |
import starling.events.Event; | |
import starling.textures.Texture; | |
import starling.textures.TextureAtlas; | |
import flash.display.Bitmap; | |
import flash.display.DisplayObject; | |
import flash.display.Loader; | |
import flash.events.Event; | |
import flash.net.URLRequest; | |
/** | |
* @author shaun.mitchell | |
*/ | |
public class TMXTileSheet extends Sprite | |
{ | |
// the name and file paths | |
private var _name:String; | |
private var _sheetFilename:String; | |
// texture, atlas and loader | |
private var _sheet:Bitmap; | |
private var _textureAtlas:TextureAtlas; | |
private var _imageLoader:Loader = new Loader(); | |
private var _startID:uint; | |
private var _tileHeight:uint; | |
private var _tileWidth:uint; | |
private var _embedded:Boolean; | |
public function TMXTileSheet():void | |
{ | |
} | |
public function loadTileSheet(name:String, sheetFile:String, tileWidth:uint, tileHeight:uint, startID:uint):void | |
{ | |
_embedded = false; | |
_name = name; | |
_sheetFilename = sheetFile; | |
_startID = startID; | |
_tileHeight = tileHeight; | |
_tileWidth = tileWidth; | |
trace("creating TMX tilesheet"); | |
_imageLoader.contentLoaderInfo.addEventListener(flash.events.Event.COMPLETE, loadSheet); | |
_imageLoader.load(new URLRequest(_sheetFilename)); | |
} | |
public function loadEmbedTileSheet(name:String, img:Bitmap, tileWidth:uint, tileHeight:uint, startID:uint):void | |
{ | |
trace("creating TMX tilesheet"); | |
_embedded = true; | |
_name = name; | |
_startID = startID; | |
_sheet = img; | |
_tileHeight = tileHeight; | |
_tileWidth = tileWidth; | |
loadAtlas(); | |
} | |
/* | |
Load the image file needed for this tilesheet | |
*/ | |
private function loadSheet(event:flash.events.Event):void | |
{ | |
var sprite:DisplayObject = _imageLoader.content; | |
_sheet = Bitmap(sprite); | |
loadAtlas(); | |
} | |
/* | |
dynamically create a texture atlas to look up tiles | |
*/ | |
private function loadAtlas():void | |
{ | |
trace("loading atlas"); | |
var numRows:uint = _sheet.height / _tileHeight; | |
var numCols:uint = _sheet.width / _tileWidth; | |
var id:int = _startID; | |
var xml:XML = <Atlas></Atlas>; | |
xml.appendChild(<TextureAtlas imagePath={_sheetFilename}></TextureAtlas>); | |
for (var i:int = 0; i < numRows; i++) | |
{ | |
for (var j:int = 0; j < numCols; j++) | |
{ | |
id++; | |
xml.child("TextureAtlas").appendChild(<SubTexture name={id} x = {j * _tileWidth} y={i * _tileHeight } width={_tileWidth} height={_tileHeight}/>); | |
} | |
} | |
var newxml:XML = XML(xml.TextureAtlas); | |
trace(newxml); | |
_textureAtlas = new TextureAtlas(Texture.fromBitmap(_sheet), newxml); | |
trace("done with atlas, dispatching"); | |
dispatchEvent(new starling.events.Event(starling.events.Event.COMPLETE)); | |
} | |
public function get sheet():Bitmap | |
{ | |
return _sheet; | |
} | |
public function get textureAtlas():TextureAtlas | |
{ | |
return _textureAtlas; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment