#Rem
#Rem
Copyright (c) 2011 Steve Revill and Shane Woolcock
Copyright (c) 2011 Steve Revill and Shane Woolcock
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#End
#End
Strict
Strict
Import xml
Import xml
Import base64
Import base64
Import mojo
Import mojo
Import brl.filepath
Import brl.filepath
' TileMapPropertyContainer
' TileMapPropertyContainer
'Summary: Classes that extend this will automatically instantiate a property container and expose it.
'Summary: Classes that extend this will automatically instantiate a property container and expose it.
Class TileMapPropertyContainer
Class TileMapPropertyContainer
Private
Private
Field properties:TileMapProperties = New TileMapProperties
Field properties:TileMapProperties = New TileMapProperties
Public
Public
Method Properties:TileMapProperties() Property
Method Properties:TileMapProperties() Property
Return properties
Return properties
End
End
End
End
' ITileMapPostLoad
' ITileMapPostLoad
'Summary: Classes that implement this interface will have PostLoad automatically called once the object has been created.
'Summary: Classes that implement this interface will have PostLoad automatically called once the object has been created.
Interface ITileMapPostLoad
Interface ITileMapPostLoad
Method PostLoad:Void()
Method PostLoad:Void()
End
End
' TileMapReader
' TileMapReader
'Summary: This can be extended to handle any map file format.
'Summary: This can be extended to handle any map file format.
Class TileMapReader Abstract
Class TileMapReader Abstract
Field tileMap:TileMap
Field tileMap:TileMap
Field graphicsPath:String
Field graphicsPath:String
Method LoadMap:TileMap(filename:String) Abstract
Method LoadMap:TileMap(filename:String) Abstract
' override this to create a custom tilemap class
' override this to create a custom tilemap class
Method CreateMap:TileMap()
Method CreateMap:TileMap()
Return New TileMap
Return New TileMap
End
End
End
End
' TiledTileMapReader
' TiledTileMapReader
'Summary: Extends TileMapReader to add support for the Tiled map editor.
'Summary: Extends TileMapReader to add support for the Tiled map editor.
Class TiledTileMapReader Extends TileMapReader
Class TiledTileMapReader Extends TileMapReader
Field doc:XMLDoc
Field doc:XMLDoc
' Overrides TileMapReader
' Overrides TileMapReader
Method LoadMap:TileMap(filename:String)
Method LoadMap:TileMap(filename:String)
' open file and get root node
' open file and get root node
Local xmlString:String = LoadString(filename)
Local xmlString:String = LoadString(filename)
' error if we couldnt load the file
' error if we couldnt load the file
If Not xmlString
If Not xmlString
Error("Cannot load tile map file " + filename + ". Ensure you have TMX in the in the allowed #TEXT_FILES")
Error("Cannot load tile map file " + filename + ". Ensure you have TMX in the in the allowed #TEXT_FILES")
End
End
' look for the data encoding, if we cant find it assume its RAW XML and thats just too slow!
' look for the data encoding, if we cant find it assume its RAW XML and thats just too slow!
Local findData:Int = xmlString.Find("<data encoding")
Local findData:Int = xmlString.Find("<data encoding")
If findData = -1
If findData = -1
Print("Tiled Raw XML is not supported!")
Print("Tiled Raw XML is not supported!")
End
End
'Set the root graphics path relative to this file's location.
graphicsPath = ExtractDir(filename) + "/"
doc = ParseXML(xmlString)
doc = ParseXML(xmlString)
Return ReadMap(doc)
Return ReadMap(doc)
End
End
Method ReadMap:TileMap(node:XMLNode)
Method ReadMap:TileMap(node:XMLNode)
tileMap = CreateMap()
tileMap = CreateMap()
ReadProperties(node, tileMap)
ReadProperties(node, tileMap)
' extract map properties
' extract map properties
If tileMap.properties.Has(PROP_MAP_WRAP_X) Then tileMap.wrapX = tileMap.properties.Get(PROP_MAP_WRAP_X).GetBool()
If tileMap.properties.Has(PROP_MAP_WRAP_X) Then tileMap.wrapX = tileMap.properties.Get(PROP_MAP_WRAP_X).GetBool()
If tileMap.properties.Has(PROP_MAP_WRAP_Y) Then tileMap.wrapY = tileMap.properties.Get(PROP_MAP_WRAP_Y).GetBool()
If tileMap.properties.Has(PROP_MAP_WRAP_Y) Then tileMap.wrapY = tileMap.properties.Get(PROP_MAP_WRAP_Y).GetBool()
' read root node's attributes
' read root node's attributes
If node.HasAttribute(ATTR_MAP_VERSION) Then tileMap.version = node.GetAttribute(ATTR_MAP_VERSION)
If node.HasAttribute(ATTR_MAP_VERSION) Then tileMap.version = node.GetAttribute(ATTR_MAP_VERSION)
If node.HasAttribute(ATTR_MAP_ORIENTATION) Then tileMap.orientation = node.GetAttribute(ATTR_MAP_ORIENTATION)
If node.HasAttribute(ATTR_MAP_ORIENTATION) Then tileMap.orientation = node.GetAttribute(ATTR_MAP_ORIENTATION)
If node.HasAttribute(ATTR_MAP_WIDTH) Then tileMap.width = Int(node.GetAttribute(ATTR_MAP_WIDTH))
If node.HasAttribute(ATTR_MAP_WIDTH) Then tileMap.width = Int(node.GetAttribute(ATTR_MAP_WIDTH))
If node.HasAttribute(ATTR_MAP_HEIGHT) Then tileMap.height = Int(node.GetAttribute(ATTR_MAP_HEIGHT))
If node.HasAttribute(ATTR_MAP_HEIGHT) Then tileMap.height = Int(node.GetAttribute(ATTR_MAP_HEIGHT))
If node.HasAttribute(ATTR_MAP_TILEWIDTH) Then tileMap.tileWidth = Int(node.GetAttribute(ATTR_MAP_TILEWIDTH))
If node.HasAttribute(ATTR_MAP_TILEWIDTH) Then tileMap.tileWidth = Int(node.GetAttribute(ATTR_MAP_TILEWIDTH))
If node.HasAttribute(ATTR_MAP_TILEHEIGHT) Then tileMap.tileHeight = Int(node.GetAttribute(ATTR_MAP_TILEHEIGHT))
If node.HasAttribute(ATTR_MAP_TILEHEIGHT) Then tileMap.tileHeight = Int(node.GetAttribute(ATTR_MAP_TILEHEIGHT))
tileMap.maxTileWidth = tileMap.tileWidth
tileMap.maxTileWidth = tileMap.tileWidth
tileMap.maxTileHeight = tileMap.tileHeight
tileMap.maxTileHeight = tileMap.tileHeight
' parse children
' parse children
If Not node.children.IsEmpty() Then
If Not node.children.IsEmpty() Then
For Local mapchild:XMLNode = Eachin node.children
For Local mapchild:XMLNode = Eachin node.children
' tileset
' tileset
If mapchild.name = NODE_TILESET Then
If mapchild.name = NODE_TILESET Then
Local ts:TileMapTileset = ReadTileset(mapchild)
Local ts:TileMapTileset = ReadTileset(mapchild)
tileMap.tilesets.Set(ts.name, ts)
tileMap.tilesets.Set(ts.name, ts)
' tile layer
' tile layer
Elseif mapchild.name = NODE_LAYER Then
Elseif mapchild.name = NODE_LAYER Then
Local layer:TileMapLayer = ReadTileLayer(mapchild)
Local layer:TileMapLayer = ReadTileLayer(mapchild)
tileMap.layers.Push(layer)
tileMap.layers.Push(layer)
' object layer
' object layer
Elseif mapchild.name = NODE_OBJECTGROUP Then
Elseif mapchild.name = NODE_OBJECTGROUP Then
Local layer:TileMapLayer = ReadObjectLayer(mapchild)
Local layer:TileMapLayer = ReadObjectLayer(mapchild)
tileMap.layers.Push(layer)
tileMap.layers.Push(layer)
Endif
Endif
Next
Next
Endif
Endif
DoPostLoad(tileMap)
DoPostLoad(tileMap)
Return tileMap
Return tileMap
End
End
Method DoPostLoad:Void(obj:Object)
Method DoPostLoad:Void(obj:Object)
If ITileMapPostLoad(obj) <> Null Then ITileMapPostLoad(obj).PostLoad()
If ITileMapPostLoad(obj) <> Null Then ITileMapPostLoad(obj).PostLoad()
End
End
Method ReadProperties:Void(node:XMLNode, obj:Object)
Method ReadProperties:Void(node:XMLNode, obj:Object)
Local cont:TileMapPropertyContainer = TileMapPropertyContainer(obj)
Local cont:TileMapPropertyContainer = TileMapPropertyContainer(obj)
If cont <> Null Then
If cont <> Null Then
For Local propNode:XMLNode = EachIn node.children
For Local propNode:XMLNode = EachIn node.children
If propNode.name = NODE_PROPERTIES Then
If propNode.name = NODE_PROPERTIES Then
For Local child:XMLNode = EachIn propNode.children
For Local child:XMLNode = EachIn propNode.children
If child.name = NODE_PROPERTY Then
If child.name = NODE_PROPERTY Then
Local prop:TileMapProperty = ReadProperty(child)
Local prop:TileMapProperty = ReadProperty(child)
cont.properties.props.Set(prop.name, prop)
cont.properties.props.Set(prop.name, prop)
Endif
Endif
Next
Next
Return
Return
End
End
Next
Next
End
End
End
End
Method ReadProperty:TileMapProperty(node:XMLNode)
Method ReadProperty:TileMapProperty(node:XMLNode)
Return New TileMapProperty(node.GetAttribute(ATTR_PROPERTY_NAME, "default"), node.GetAttribute(ATTR_PROPERTY_VALUE, ""))
Return New TileMapProperty(node.GetAttribute(ATTR_PROPERTY_NAME, "default"), node.GetAttribute(ATTR_PROPERTY_VALUE, ""))
End
End
Method ReadTileset:TileMapTileset(node:XMLNode, target:TileMapTileset=Null)
Method ReadTileset:TileMapTileset(node:XMLNode, target:TileMapTileset=Null)
Local rv:TileMapTileset = target
Local rv:TileMapTileset = target
ReadProperties(node, rv)
ReadProperties(node, rv)
If rv = Null Then rv = tileMap.CreateTileset()
If rv = Null Then rv = tileMap.CreateTileset()
If node.HasAttribute(ATTR_TILESET_FIRSTGID) Then rv.firstGid = Int(node.GetAttribute(ATTR_TILESET_FIRSTGID))
If node.HasAttribute(ATTR_TILESET_FIRSTGID) Then rv.firstGid = Int(node.GetAttribute(ATTR_TILESET_FIRSTGID))
If node.HasAttribute(ATTR_TILESET_SOURCE) Then
If node.HasAttribute(ATTR_TILESET_SOURCE) Then
rv.source = node.GetAttribute(ATTR_TILESET_SOURCE)
rv.source = node.GetAttribute(ATTR_TILESET_SOURCE)
Local tilesetdoc:XMLDoc = ParseXML(LoadString(rv.source)) 'Note: Fragile... Let's make this more robust later -nobu
Local tilesetdoc:XMLDoc = ParseXML(LoadString(rv.source)) 'Note: Fragile... Let's make this more robust later -nobu
Return ReadTileset(tilesetdoc, rv)
Return ReadTileset(tilesetdoc, rv)
Else
Else
If node.HasAttribute(ATTR_TILESET_NAME) Then rv.name = node.GetAttribute(ATTR_TILESET_NAME)
If node.HasAttribute(ATTR_TILESET_NAME) Then rv.name = node.GetAttribute(ATTR_TILESET_NAME)
If node.HasAttribute(ATTR_TILESET_TILEWIDTH) Then rv.tileWidth = Int(node.GetAttribute(ATTR_TILESET_TILEWIDTH))
If node.HasAttribute(ATTR_TILESET_TILEWIDTH) Then rv.tileWidth = Int(node.GetAttribute(ATTR_TILESET_TILEWIDTH))
If node.HasAttribute(ATTR_TILESET_TILEHEIGHT) Then rv.tileHeight = Int(node.GetAttribute(ATTR_TILESET_TILEHEIGHT))
If node.HasAttribute(ATTR_TILESET_TILEHEIGHT) Then rv.tileHeight = Int(node.GetAttribute(ATTR_TILESET_TILEHEIGHT))
If node.HasAttribute(ATTR_TILESET_SPACING) Then rv.spacing = Int(node.GetAttribute(ATTR_TILESET_SPACING))
If node.HasAttribute(ATTR_TILESET_SPACING) Then rv.spacing = Int(node.GetAttribute(ATTR_TILESET_SPACING))
If node.HasAttribute(ATTR_TILESET_MARGIN) Then rv.margin = Int(node.GetAttribute(ATTR_TILESET_MARGIN))
If node.HasAttribute(ATTR_TILESET_MARGIN) Then rv.margin = Int(node.GetAttribute(ATTR_TILESET_MARGIN))
If Not node.children.IsEmpty() Then
If Not node.children.IsEmpty() Then
For Local child:XMLNode = Eachin node.children
For Local child:XMLNode = Eachin node.children
If child.name = NODE_IMAGE Then
If child.name = NODE_IMAGE Then
rv.imageNode = ReadImage(child)
rv.imageNode = ReadImage(child)
Elseif child.name = NODE_TILE Then
Elseif child.name = NODE_TILE Then
rv.tileNodes.Push(ReadTile(child))
rv.tileNodes.Push(ReadTile(child))
End
End
Next
Next
End
End
End
End
DoPostLoad(rv)
DoPostLoad(rv)
Return rv
Return rv
End
End
Method ReadLayerAttributes:Void(node:XMLNode, layer:TileMapLayer)
Method ReadLayerAttributes:Void(node:XMLNode, layer:TileMapLayer)
If node.HasAttribute(ATTR_LAYER_NAME) Then layer.name = node.GetAttribute(ATTR_LAYER_NAME)
If node.HasAttribute(ATTR_LAYER_NAME) Then layer.name = node.GetAttribute(ATTR_LAYER_NAME)
If node.HasAttribute(ATTR_LAYER_WIDTH) Then layer.width = Int(node.GetAttribute(ATTR_LAYER_WIDTH))
If node.HasAttribute(ATTR_LAYER_WIDTH) Then layer.width = Int(node.GetAttribute(ATTR_LAYER_WIDTH))
If node.HasAttribute(ATTR_LAYER_HEIGHT) Then layer.height = Int(node.GetAttribute(ATTR_LAYER_HEIGHT))
If node.HasAttribute(ATTR_LAYER_HEIGHT) Then layer.height = Int(node.GetAttribute(ATTR_LAYER_HEIGHT))
layer.visible = Not node.HasAttribute(ATTR_LAYER_VISIBLE) Or Int(node.GetAttribute(ATTR_LAYER_VISIBLE)) <> 0
layer.visible = Not node.HasAttribute(ATTR_LAYER_VISIBLE) Or Int(node.GetAttribute(ATTR_LAYER_VISIBLE)) <> 0
If node.HasAttribute(ATTR_LAYER_OPACITY) Then layer.opacity = Float(node.GetAttribute(ATTR_LAYER_OPACITY))
If node.HasAttribute(ATTR_LAYER_OPACITY) Then layer.opacity = Float(node.GetAttribute(ATTR_LAYER_OPACITY))
End
End
Method ReadTileLayer:TileMapTileLayer(node:XMLNode)
Method ReadTileLayer:TileMapTileLayer(node:XMLNode)
Local rv:TileMapTileLayer = tileMap.CreateTileLayer()
Local rv:TileMapTileLayer = tileMap.CreateTileLayer()
ReadProperties(node, rv)
ReadProperties(node, rv)
ReadLayerAttributes(node, rv)
ReadLayerAttributes(node, rv)
If rv.properties.Has(PROP_LAYER_PARALLAX_OFFSET_X) Then rv.parallaxOffsetX = rv.properties.Get(PROP_LAYER_PARALLAX_OFFSET_X).GetFloat()
If rv.properties.Has(PROP_LAYER_PARALLAX_OFFSET_X) Then rv.parallaxOffsetX = rv.properties.Get(PROP_LAYER_PARALLAX_OFFSET_X).GetFloat()
If rv.properties.Has(PROP_LAYER_PARALLAX_OFFSET_Y) Then rv.parallaxOffsetY = rv.properties.Get(PROP_LAYER_PARALLAX_OFFSET_Y).GetFloat()
If rv.properties.Has(PROP_LAYER_PARALLAX_OFFSET_Y) Then rv.parallaxOffsetY = rv.properties.Get(PROP_LAYER_PARALLAX_OFFSET_Y).GetFloat()
If rv.properties.Has(PROP_LAYER_PARALLAX_SCALE_X) Then rv.parallaxScaleX = rv.properties.Get(PROP_LAYER_PARALLAX_SCALE_X).GetFloat()
If rv.properties.Has(PROP_LAYER_PARALLAX_SCALE_X) Then rv.parallaxScaleX = rv.properties.Get(PROP_LAYER_PARALLAX_SCALE_X).GetFloat()
If rv.properties.Has(PROP_LAYER_PARALLAX_SCALE_Y) Then rv.parallaxScaleY = rv.properties.Get(PROP_LAYER_PARALLAX_SCALE_Y).GetFloat()
If rv.properties.Has(PROP_LAYER_PARALLAX_SCALE_Y) Then rv.parallaxScaleY = rv.properties.Get(PROP_LAYER_PARALLAX_SCALE_Y).GetFloat()
If rv.properties.Has(PROP_MAP_WRAP_X) Then rv.wrapX = rv.properties.Get(PROP_MAP_WRAP_X).GetBool()
If rv.properties.Has(PROP_MAP_WRAP_Y) Then rv.wrapY = rv.properties.Get(PROP_MAP_WRAP_Y).GetBool()
For Local child:XMLNode = Eachin node.children
For Local child:XMLNode = Eachin node.children
If child.name = NODE_DATA Then
If child.name = NODE_DATA Then
rv.mapData = ReadTileData(child, rv)
rv.mapData = ReadTileData(child, rv)
End
End
Next
Next
DoPostLoad(rv)
DoPostLoad(rv)
Return rv
Return rv
End
End
Method ReadObjectLayer:TileMapObjectLayer(node:XMLNode)
Method ReadObjectLayer:TileMapObjectLayer(node:XMLNode)
Local rv:TileMapObjectLayer = tileMap.CreateObjectLayer()
Local rv:TileMapObjectLayer = tileMap.CreateObjectLayer()
ReadProperties(node, rv)
ReadProperties(node, rv)
ReadLayerAttributes(node, rv)
ReadLayerAttributes(node, rv)
If node.HasAttribute(ATTR_OBJECTGROUP_COLOR) Then rv.color = ColorToInt(node.GetAttribute(ATTR_OBJECTGROUP_COLOR))
If node.HasAttribute(ATTR_OBJECTGROUP_COLOR) Then rv.color = ColorToInt(node.GetAttribute(ATTR_OBJECTGROUP_COLOR))
For Local child:XMLNode = Eachin node.children
For Local child:XMLNode = Eachin node.children
If child.name = NODE_OBJECT Then
If child.name = NODE_OBJECT Then
rv.objects.Push(ReadObject(child, rv))
rv.objects.Push(ReadObject(child, rv))
End
End
Next
Next
DoPostLoad(rv)
DoPostLoad(rv)
Return rv
Return rv
End
End
Method ReadImage:TileMapImage(node:XMLNode)
Method ReadImage:TileMapImage(node:XMLNode)
Local rv:TileMapImage = tileMap.CreateImage()
Local rv:TileMapImage = tileMap.CreateImage()
ReadProperties(node, rv)
ReadProperties(node, rv)
If node.HasAttribute(ATTR_IMAGE_SOURCE) Then rv.source = graphicsPath + StripDir(node.GetAttribute(ATTR_IMAGE_SOURCE))
If node.HasAttribute(ATTR_IMAGE_SOURCE) Then 'Try to find a valid graphics resource.
Local src:= node.GetAttribute(ATTR_IMAGE_SOURCE)
If src[0 .. 7].Contains(":/") Or src[0 .. 7].Contains(":\") 'Hardcoded path or URL.
rv.source = src
Else 'Relative path. Use graphicsPath from loaded mapfile.
rv.source = graphicsPath + src
End If
End If
If node.HasAttribute(ATTR_IMAGE_WIDTH) Then rv.width = Int(node.GetAttribute(ATTR_IMAGE_WIDTH))
If node.HasAttribute(ATTR_IMAGE_WIDTH) Then rv.width = Int(node.GetAttribute(ATTR_IMAGE_WIDTH))
If node.HasAttribute(ATTR_IMAGE_HEIGHT) Then rv.height = Int(node.GetAttribute(ATTR_IMAGE_HEIGHT))
If node.HasAttribute(ATTR_IMAGE_HEIGHT) Then rv.height = Int(node.GetAttribute(ATTR_IMAGE_HEIGHT))
If node.HasAttribute(ATTR_IMAGE_TRANS) Then rv.trans = node.GetAttribute(ATTR_IMAGE_TRANS)
If node.HasAttribute(ATTR_IMAGE_TRANS) Then rv.trans = node.GetAttribute(ATTR_IMAGE_TRANS)
If rv.trans.Length > 0 Then
If rv.trans.Length > 0 Then
rv.transR = HexToDec(rv.trans[0..2])
rv.transR = HexToDec(rv.trans[0..2])
rv.transG = HexToDec(rv.trans[2..4])
rv.transG = HexToDec(rv.trans[2..4])
rv.transB = HexToDec(rv.trans[4..6])
rv.transB = HexToDec(rv.trans[4..6])
Endif
Endif
DoPostLoad(rv)
DoPostLoad(rv)
Return rv
Return rv
End
End
Method ReadTile:TileMapTile(node:XMLNode)
Method ReadTile:TileMapTile(node:XMLNode)
Local id:Int = Int(node.GetAttribute(ATTR_TILE_ID, "0"))
Local id:Int = Int(node.GetAttribute(ATTR_TILE_ID, "0"))
Local rv:TileMapTile = tileMap.CreateTile(id)
Local rv:TileMapTile = tileMap.CreateTile(id)
ReadProperties(node, rv)
ReadProperties(node, rv)
DoPostLoad(rv)
DoPostLoad(rv)
Return rv
Return rv
End
End
Method ReadObject:TileMapObject(node:XMLNode, layer:TileMapObjectLayer)
Method ReadObject:TileMapObject(node:XMLNode, layer:TileMapObjectLayer)
Local rv:TileMapObject = tileMap.CreateObject()
Local rv:TileMapObject = tileMap.CreateObject()
ReadProperties(node, rv)
ReadProperties(node, rv)
If node.HasAttribute(ATTR_OBJECT_NAME) Then rv.name = node.GetAttribute(ATTR_OBJECT_NAME)
If node.HasAttribute(ATTR_OBJECT_NAME) Then rv.name = node.GetAttribute(ATTR_OBJECT_NAME)
If node.HasAttribute(ATTR_OBJECT_TYPE) Then rv.objectType = node.GetAttribute(ATTR_OBJECT_TYPE)
If node.HasAttribute(ATTR_OBJECT_TYPE) Then rv.objectType = node.GetAttribute(ATTR_OBJECT_TYPE)
If node.HasAttribute(ATTR_OBJECT_X) Then rv.x = Int(node.GetAttribute(ATTR_OBJECT_X))
If node.HasAttribute(ATTR_OBJECT_X) Then rv.x = Int(node.GetAttribute(ATTR_OBJECT_X))
If node.HasAttribute(ATTR_OBJECT_Y) Then rv.y = Int(node.GetAttribute(ATTR_OBJECT_Y))
If node.HasAttribute(ATTR_OBJECT_Y) Then rv.y = Int(node.GetAttribute(ATTR_OBJECT_Y))
If node.HasAttribute(ATTR_OBJECT_WIDTH) Then rv.width = Int(node.GetAttribute(ATTR_OBJECT_WIDTH))
If node.HasAttribute(ATTR_OBJECT_WIDTH) Then rv.width = Int(node.GetAttribute(ATTR_OBJECT_WIDTH))
If node.HasAttribute(ATTR_OBJECT_HEIGHT) Then rv.height = Int(node.GetAttribute(ATTR_OBJECT_HEIGHT))
If node.HasAttribute(ATTR_OBJECT_HEIGHT) Then rv.height = Int(node.GetAttribute(ATTR_OBJECT_HEIGHT))
DoPostLoad(rv)
DoPostLoad(rv)
Return rv
Return rv
End
End
Method ReadTileData:TileMapData(node:XMLNode, layer:TileMapTileLayer)
Method ReadTileData:TileMapData(node:XMLNode, layer:TileMapTileLayer)
Local rv:TileMapData = tileMap.CreateData(layer.width, layer.height)
Local rv:TileMapData = tileMap.CreateData(layer.width, layer.height)
' default to raw xml (ugly)
' default to raw xml (ugly)
Local encoding$ = DATA_ENCODING_RAW
Local encoding$ = DATA_ENCODING_RAW
If node.HasAttribute(ATTR_DATA_ENCODING) Then encoding = node.GetAttribute(ATTR_DATA_ENCODING)
If node.HasAttribute(ATTR_DATA_ENCODING) Then encoding = node.GetAttribute(ATTR_DATA_ENCODING)
If encoding = DATA_ENCODING_RAW Then
If encoding = DATA_ENCODING_RAW Then
' TODO: raw xml
' TODO: raw xml
Error("TileMap: Raw xml is currently not supported")
Error("TileMap: Raw xml is currently not supported")
Elseif encoding = DATA_ENCODING_CSV Then
Elseif encoding = DATA_ENCODING_CSV Then
Local csv:String[] = node.value.Split(",")
Local csv:String[] = node.value.Split(",")
For Local i% = 0 Until csv.Length
For Local i% = 0 Until csv.Length
Local gid:Int = Int(csv[i].Trim())
Local gid:Int = Int(csv[i].Trim())
rv.tiles[i] = gid
rv.tiles[i] = gid
rv.cells[i] = tileMap.CreateCell(gid, i Mod rv.width, i / rv.width)
rv.cells[i] = tileMap.CreateCell(gid, i Mod rv.width, i / rv.width)
Next
Next
Elseif encoding = DATA_ENCODING_BASE64 Then
Elseif encoding = DATA_ENCODING_BASE64 Then
Local bytes:Int[] = DecodeBase64Bytes(node.value)
Local bytes:Int[] = DecodeBase64Bytes(node.value)
If node.HasAttribute(ATTR_DATA_COMPRESSION) Then
If node.HasAttribute(ATTR_DATA_COMPRESSION) Then
' TODO: compression
' TODO: compression
Error("TileMap: Compression is currently not supported")
Error("TileMap: Compression is currently not supported")
End
End
For Local i% = 0 Until bytes.Length Step 4
For Local i% = 0 Until bytes.Length Step 4
' little endian
' little endian
Local gid% = bytes[i]
Local gid% = bytes[i]
gid += bytes[i + 1] Shl 8
gid += bytes[i + 1] Shl 8
gid += bytes[i + 2] Shl 16
gid += bytes[i + 2] Shl 16
gid += bytes[i + 3] Shl 24
gid += bytes[i + 3] Shl 24
rv.tiles[i / 4] = gid
rv.tiles[i / 4] = gid
rv.cells[i / 4] = tileMap.CreateCell(gid, (i / 4) Mod rv.width, (i / 4) / rv.width)
rv.cells[i / 4] = tileMap.CreateCell(gid, (i / 4) Mod rv.width, (i / 4) / rv.width)
Next
Next
End
End
Return rv
Return rv
End
End
End
End
' TileMapProperties
' TileMapProperties
' Container for properties.
' Container for properties.
Class TileMapProperties
Class TileMapProperties
Field props:StringMap<TileMapProperty> = New StringMap<TileMapProperty>
Field props:StringMap<TileMapProperty> = New StringMap<TileMapProperty>
Method Has:Bool(name:String)
Method Has:Bool(name:String)
Return props.Contains(name)
Return props.Contains(name)
End
End
Method Get:TileMapProperty(name:String)
Method Get:TileMapProperty(name:String)
Return props.Get(name)
Return props.Get(name)
End
End
Method Set:Void(name:String, prop:TileMapProperty)
Method Set:Void(name:String, prop:TileMapProperty)
props.Set(name, prop)
props.Set(name, prop)
End
End
End
End
' TileMap
' TileMap
' The main Map class.
' The main Map class.
Class TileMap Extends TileMapPropertyContainer Implements ITileMapPostLoad
Class TileMap Extends TileMapPropertyContainer Implements ITileMapPostLoad
' attributes
' attributes
Field version:String = "1.0"
Field version:String = "1.0"
Field orientation:String = MAP_ORIENTATION_ORTHOGONAL
Field orientation:String = MAP_ORIENTATION_ORTHOGONAL
Field width:Int
Field width:Int
Field height:Int
Field height:Int
Field tileWidth:Int = 32
Field tileWidth:Int = 32
Field tileHeight:Int = 32
Field tileHeight:Int = 32
' children
' children
Field tilesets:StringMap<TileMapTileset> = New StringMap<TileMapTileset>
Field tilesets:StringMap<TileMapTileset> = New StringMap<TileMapTileset>
Field layers:Stack<TileMapLayer> = New Stack<TileMapLayer>
Field layers:Stack<TileMapLayer> = New Stack<TileMapLayer>
' post-load
' post-load
Field layerNames:StringMap<TileMapLayer> = New StringMap<TileMapLayer>
Field layerNames:StringMap<TileMapLayer> = New StringMap<TileMapLayer>
Field tiles:TileMapTile[]
Field tiles:TileMapTile[]
Field maxTileWidth:Int
Field maxTileWidth:Int
Field maxTileHeight:Int
Field maxTileHeight:Int
Field wrapX:Bool = False
Field wrapX:Bool = False
Field wrapY:Bool = False
Field wrapY:Bool = False
' optimisation
' optimisation
Field layerArray:TileMapLayer[] = []
Field layerArray:TileMapLayer[] = []
Field animatedTiles:TileMapTile[]
Field animatedTiles:TileMapTile[]
' summary: override this to do something before a layer is rendered
' summary: override this to do something before a layer is rendered
Method PreRenderLayer:Void(tileLayer:TileMapLayer)
Method PreRenderLayer:Void(tileLayer:TileMapLayer)
ConfigureLayer(tileLayer) ' call the deprecated one
ConfigureLayer(tileLayer) ' call the deprecated one
End
End
' summary: override this to do something after a layer is rendered
' summary: override this to do something after a layer is rendered
Method PostRenderLayer:Void(tileLayer:TileMapLayer)
Method PostRenderLayer:Void(tileLayer:TileMapLayer)
End
End
' summary: override this to do something before the map is rendered
' summary: override this to do something before the map is rendered
Method PreRenderMap:Void()
Method PreRenderMap:Void()
End
End
'summary: override this to do something after the map is rendered
'summary: override this to do something after the map is rendered
Method PostRenderMap:Void()
Method PostRenderMap:Void()
End
End
'summary: override this to configure a layer (called on every render) 'deprecated, override PreRenderLayer instead
'summary: override this to configure a layer (called on every render) 'deprecated, override PreRenderLayer instead
Method ConfigureLayer:Void(tileLayer:TileMapLayer)
Method ConfigureLayer:Void(tileLayer:TileMapLayer)
End
End
'summary: override this to draw a tile
'summary: override this to draw a tile
Method DrawTile:Void(tileLayer:TileMapTileLayer, mapTile:TileMapTile, x:Int, y:Int)
Method DrawTile:Void(tileLayer:TileMapTileLayer, mapTile:TileMapTile, x:Int, y:Int)
If mapTile.rawImage Then
If mapTile.rawImage Then
DrawImageRect(mapTile.rawImage, x, y, mapTile.srcX, mapTile.srcY, mapTile.width, mapTile.height, 0, 1, 1)
DrawImageRect(mapTile.rawImage, x, y, mapTile.srcX, mapTile.srcY, mapTile.width, mapTile.height, 0, 1, 1)
End
End
End
End
'summary: override this to create a custom tile class
'summary: override this to create a custom tile class
Method CreateTile:TileMapTile(id:Int)
Method CreateTile:TileMapTile(id:Int)
Return New TileMapTile(id)
Return New TileMapTile(id)
End
End
'summary: override this to create a custom tileset class
'summary: override this to create a custom tileset class
Method CreateTileset:TileMapTileset()
Method CreateTileset:TileMapTileset()
Return New TileMapTileset
Return New TileMapTileset
End
End
'summary: override this to create a custom tile layer class
'summary: override this to create a custom tile layer class
Method CreateTileLayer:TileMapTileLayer()
Method CreateTileLayer:TileMapTileLayer()
Return New TileMapTileLayer
Return New TileMapTileLayer
End
End
'summary: override this to create a custom object layer class
'summary: override this to create a custom object layer class
Method CreateObjectLayer:TileMapObjectLayer()
Method CreateObjectLayer:TileMapObjectLayer()
Return New TileMapObjectLayer
Return New TileMapObjectLayer
End
End
'summary: override this to create a custom image class
'summary: override this to create a custom image class
Method CreateImage:TileMapImage()
Method CreateImage:TileMapImage()
Return New TileMapImage
Return New TileMapImage
End
End
'summary: override this to create a custom object class
'summary: override this to create a custom object class
Method CreateObject:TileMapObject()
Method CreateObject:TileMapObject()
Return New TileMapObject
Return New TileMapObject
End
End
'summary: override this to create a custom cell class
'summary: override this to create a custom cell class
Method CreateCell:TileMapCell(gid:Int, x:Int, y:Int)
Method CreateCell:TileMapCell(gid:Int, x:Int, y:Int)
Return New TileMapCell(gid, x, y)
Return New TileMapCell(gid, x, y)
End
End
'summary: override this to create a custom data class
'summary: override this to create a custom data class
Method CreateData:TileMapData(width:Int, height:Int)
Method CreateData:TileMapData(width:Int, height:Int)
Return New TileMapData(width, height)
Return New TileMapData(width, height)
End
End
'summary: override this to perform additional post-loading functionality (remember to call Super.PostLoad() first)
'summary: override this to perform additional post-loading functionality (remember to call Super.PostLoad() first)
Method PostLoad:Void()
Method PostLoad:Void()
Local totaltiles% = 0, ts:TileMapTileset
Local totaltiles% = 0, ts:TileMapTileset
Local alltiles:Stack<TileMapTile> = New Stack<TileMapTile>
Local alltiles:Stack<TileMapTile> = New Stack<TileMapTile>
For Local ts:TileMapTileset = EachIn tilesets.Values()
For Local ts:TileMapTileset = EachIn tilesets.Values()
'TODO: Add an option here to try to load from a prefetch atlas asset instead.
'TODO: Add an option here to try to load from a prefetch atlas asset instead.
'For now, load it with LoadImage
'For now, load it with LoadImage
ts.rawImage = LoadImage(ts.imageNode.source)
ts.rawImage = LoadImage(ts.imageNode.source)
If ts.rawImage Then
If ts.rawImage Then
ts.tileCountX = (ts.rawImage.Width() - ts.margin) / (ts.tileWidth + ts.spacing)
ts.tileCountX = (ts.rawImage.Width() - ts.margin) / (ts.tileWidth + ts.spacing)
ts.tileCountY = (ts.rawImage.Height() - ts.margin) / (ts.tileHeight + ts.spacing)
ts.tileCountY = (ts.rawImage.Height() - ts.margin) / (ts.tileHeight + ts.spacing)
ts.tileCount = ts.tileCountX * ts.tileCountY
ts.tileCount = ts.tileCountX * ts.tileCountY
Else
Else
Print "Couldn't find tileset image: "+ts.imageNode.source
Print("Tilemap: WARNING, Couldn't find tileset image: " + ts.imageNode.source)
Return
Return
End
End
' update max tile size
' update max tile size
If maxTileWidth < ts.tileWidth Then maxTileWidth = ts.tileWidth
If maxTileWidth < ts.tileWidth Then maxTileWidth = ts.tileWidth
If maxTileHeight < ts.tileHeight Then maxTileHeight = ts.tileHeight
If maxTileHeight < ts.tileHeight Then maxTileHeight = ts.tileHeight
' build tile list
' build tile list
ts.tiles = New TileMapTile[ts.tileCount]
ts.tiles = New TileMapTile[ts.tileCount]
For Local t:TileMapTile = Eachin ts.tileNodes
For Local t:TileMapTile = Eachin ts.tileNodes
ts.tiles[t.id] = t
ts.tiles[t.id] = t
Next
Next
For Local i% = 0 Until ts.tiles.Length
For Local i% = 0 Until ts.tiles.Length
If ts.tiles[i] = Null Then
If ts.tiles[i] = Null Then
ts.tiles[i] = CreateTile(i)
ts.tiles[i] = CreateTile(i)
End
End
ts.tiles[i].gid = ts.firstGid + i
ts.tiles[i].gid = ts.firstGid + i
' ts.tiles[i].image = ts.image
' ts.tiles[i].image = ts.image
ts.tiles[i].rawImage = ts.rawImage
ts.tiles[i].rawImage = ts.rawImage
ts.tiles[i].width = ts.tileWidth
ts.tiles[i].width = ts.tileWidth
ts.tiles[i].height = ts.tileHeight
ts.tiles[i].height = ts.tileHeight
' if we're using the raw image we need to precache some stuff
' if we're using the raw image we need to precache some stuff
If ts.rawImage Then
If ts.rawImage Then
ts.tiles[i].srcX = ts.margin + (ts.tileWidth + ts.spacing) * (i Mod ts.tileCountX)
ts.tiles[i].srcX = ts.margin + (ts.tileWidth + ts.spacing) * (i Mod ts.tileCountX)
ts.tiles[i].srcY = ts.margin + (ts.tileHeight + ts.spacing) * (i / ts.tileCountX)
ts.tiles[i].srcY = ts.margin + (ts.tileHeight + ts.spacing) * (i / ts.tileCountX)
End
End
alltiles.Push(ts.tiles[i])
alltiles.Push(ts.tiles[i])
Next
Next
' update total tiles
' update total tiles
totaltiles += ts.tileCount
totaltiles += ts.tileCount
Next
Next
' make our cache
' make our cache
tiles = New TileMapTile[totaltiles]
tiles = New TileMapTile[totaltiles]
For Local t:TileMapTile = Eachin alltiles
For Local t:TileMapTile = Eachin alltiles
tiles[t.gid - 1] = t
tiles[t.gid - 1] = t
Next
Next
' calculate the max tile size per layer
' calculate the max tile size per layer
For Local l:TileMapLayer = Eachin layers
For Local l:TileMapLayer = Eachin layers
If TileMapTileLayer(l) <> Null Then
If TileMapTileLayer(l) <> Null Then
Local tl:TileMapTileLayer = TileMapTileLayer(l)
Local tl:TileMapTileLayer = TileMapTileLayer(l)
For Local i% = 0 Until tl.mapData.tiles.Length
For Local i% = 0 Until tl.mapData.tiles.Length
If tl.mapData.tiles[i] > 0 Then
If tl.mapData.tiles[i] > 0 Then
If tl.maxTileWidth < tiles[tl.mapData.tiles[i] - 1].width Then tl.maxTileWidth = tiles[tl.mapData.tiles[i] - 1].width
If tl.maxTileWidth < tiles[tl.mapData.tiles[i] - 1].width Then tl.maxTileWidth = tiles[tl.mapData.tiles[i] - 1].width
If tl.maxTileHeight < tiles[tl.mapData.tiles[i] - 1].height Then tl.maxTileHeight = tiles[tl.mapData.tiles[i] - 1].height
If tl.maxTileHeight < tiles[tl.mapData.tiles[i] - 1].height Then tl.maxTileHeight = tiles[tl.mapData.tiles[i] - 1].height
End
End
Next
Next
End
End
Next
Next
End
End
Method GetAllObjects:Stack<TileMapObject>()
Method GetAllObjects:Stack<TileMapObject>()
Local rv:Stack<TileMapObject> = New Stack<TileMapObject>
Local rv:Stack<TileMapObject> = New Stack<TileMapObject>
For Local layer:TileMapLayer = EachIn layers
For Local layer:TileMapLayer = EachIn layers
If TileMapObjectLayer(layer) <> Null Then
If TileMapObjectLayer(layer) <> Null Then
For Local obj:TileMapObject = EachIn TileMapObjectLayer(layer).objects
For Local obj:TileMapObject = EachIn TileMapObjectLayer(layer).objects
rv.Push(obj)
rv.Push(obj)
Next
Next
End
End
Next
Next
Return rv
Return rv
End
End
Method FindObjectByName:TileMapObject(name:String)
Method FindObjectByName:TileMapObject(name:String)
For Local layer:TileMapLayer = EachIn layers
For Local layer:TileMapLayer = EachIn layers
If TileMapObjectLayer(layer) <> Null Then
If TileMapObjectLayer(layer) <> Null Then
For Local obj:TileMapObject = EachIn TileMapObjectLayer(layer).objects
For Local obj:TileMapObject = EachIn TileMapObjectLayer(layer).objects
If obj.name = name Then Return obj
If obj.name = name Then Return obj
Next
Next
EndIf
EndIf
Next
Next
Return Null
Return Null
End
End
Method RenderLayer:Void(layerName:String, bx:Int, by:Int, bw:Int, bh:Int, sx:Float = 1, sy:Float = 1, offsetX:Float = 0, offsetY:Float = 0)
Method RenderLayer:Void(layerName:String, bx:Int, by:Int, bw:Int, bh:Int, sx:Float = 1, sy:Float = 1, offsetX:Float = 0, offsetY:Float = 0)
Local layer:TileMapLayer
Local layer:TileMapLayer
For Local l:TileMapLayer = EachIn layers
For Local l:TileMapLayer = EachIn layers
If l.name.ToUpper() = layerName.ToUpper()
If l.name.ToUpper() = layerName.ToUpper()
layer = l
layer = l
Exit
Exit
End
End
End
End
RenderLayer(layer, bx, by, bw, bh, sx, sy, offsetX, offsetY)
RenderLayer(layer, bx, by, bw, bh, sx, sy, offsetX, offsetY)
End
End
' bx,by: top-left corner of the viewport
' bx,by: top-left corner of the viewport
' bw,bh: dimensions of the viewport
' bw,bh: dimensions of the viewport
' sx,xy: scale when rendering tiles
' sx,xy: scale when rendering tiles
' offsetX,offsetY: the point in the UNSCALED map that should appear in the top-left corner
' offsetX,offsetY: the point in the UNSCALED map that should appear in the top-left corner
' tiles will be rendered as if the target location were 0,0 in the viewport, and the scaling handle is at offsetX, offsetY
' tiles will be rendered as if the target location were 0,0 in the viewport, and the scaling handle is at offsetX, offsetY
Method RenderLayer:Void(layer:TileMapLayer, bx:Int, by:Int, bw:Int, bh:Int, sx:Float = 1, sy:Float = 1, offsetX:Float = 0, offsetY:Float = 0)
Method RenderLayer:Void(layer:TileMapLayer, bx:Int, by:Int, bw:Int, bh:Int, sx:Float = 1, sy:Float = 1, offsetX:Float = 0, offsetY:Float = 0)
If layer.visible And TileMapTileLayer(layer) <> Null Then
If layer.visible And TileMapTileLayer(layer) <> Null Then
Local tl:TileMapTileLayer = TileMapTileLayer(layer)
Local tl:TileMapTileLayer = TileMapTileLayer(layer)
'Local mapTile:TileMapTile, gid%
'Local mapTile:TileMapTile, gid%
PreRenderLayer(layer)
PreRenderLayer(layer)
PushMatrix()
PushMatrix()
Translate(bx, by)
Translate(bx, by)
Scale(sx, sy)
Scale(sx, sy)
' ortho
' ortho
If orientation = MAP_ORIENTATION_ORTHOGONAL Then
If orientation = MAP_ORIENTATION_ORTHOGONAL Then
' size of the scaled tiles
' size of the scaled tiles
Local scaledTileWidth:Float = tl.maxTileWidth * sx
Local scaledTileWidth:Float = tl.maxTileWidth * sx
Local scaledTileHeight:Float = tl.maxTileHeight * sy
Local scaledTileHeight:Float = tl.maxTileHeight * sy
' the range of tiles that are visible, based on the scale and parallax
' the range of tiles that are visible, based on the scale and parallax
Local startMapX:Int = (offsetX * tl.parallaxScaleX / tl.maxTileWidth) - 1
Local startMapX:Int = (offsetX * tl.parallaxScaleX / tl.maxTileWidth) - 1
Local startMapY:Int = (offsetY * tl.parallaxScaleY / tl.maxTileHeight) - 1
Local startMapY:Int = (offsetY * tl.parallaxScaleY / tl.maxTileHeight) - 1
Local endMapX:Int = startMapX + (bw / scaledTileWidth) + 2
Local endMapX:Int = startMapX + (bw / scaledTileWidth) + 2
Local endMapY:Int = startMapY + (bh / scaledTileHeight) + 2
Local endMapY:Int = startMapY + (bh / scaledTileHeight) + 2
'Print "x,y,x,y="+startMapX+","+startMapY+","+endMapX+","+endMapY
'Print "x,y,x,y="+startMapX+","+startMapY+","+endMapX+","+endMapY
' loop on potentially visible tiles (y direction)
' loop on potentially visible tiles (y direction)
For Local my:Int = startMapY To endMapY
For Local my:Int = startMapY To endMapY
Local my2:Int = my
Local my2:Int = my
' wrap y direction if necessary
' wrap y direction if necessary
If wrapY Then
If wrapY Or tl.wrapY Then
While my2 < 0; my2 += height; End
While my2 < 0; my2 += height; End
While my2 >= height; my2 -= height; End
While my2 >= height; my2 -= height; End
End
End
' loop on potentially visible tiles (x direction)
' loop on potentially visible tiles (x direction)
For Local mx:Int = startMapX To endMapX
For Local mx:Int = startMapX To endMapX
Local mx2:Int = mx
Local mx2:Int = mx
' wrap x direction if necessary
' wrap x direction if necessary
If wrapX Then
If wrapX Or tl.wrapX Then
While mx2 < 0; mx2 += width; End
While mx2 < 0; mx2 += width; End
While mx2 >= width; mx2 -= width; End
While mx2 >= width; mx2 -= width; End
End
End
' check the range
' check the range
If mx2 >= 0 And mx2 < width And my2 >= 0 And my2 < height Then
If mx2 >= 0 And mx2 < width And my2 >= 0 And my2 < height Then
' get the global id
' get the global id
Local gid:Int = tl.mapData.cells[mx2 + my2 * tl.mapData.width].gid
Local gid:Int = tl.mapData.cells[mx2 + my2 * tl.mapData.width].gid
' if we have an id
' if we have an id
If gid > 0 Then
If gid > 0 Then
' get the tile
' get the tile
Local mapTile:TileMapTile = tiles[gid - 1]
Local mapTile:TileMapTile = tiles[gid - 1]
' work out the render position based on tile sizes, parallax, and offset
' work out the render position based on tile sizes, parallax, and offset
' rendering scale is handled automatically by the transformation matrix
' rendering scale is handled automatically by the transformation matrix
Local rx:Int = mx * tl.maxTileWidth - offsetX * tl.parallaxScaleX
Local rx:Int = mx * tl.maxTileWidth - offsetX * tl.parallaxScaleX
Local ry:Int = my * tl.maxTileHeight - offsetY * tl.parallaxScaleY
Local ry:Int = my * tl.maxTileHeight - offsetY * tl.parallaxScaleY
DrawTile(tl, mapTile, rx, ry)
DrawTile(tl, mapTile, rx, ry)
End
End
End
End
Next
Next
Next
Next
' iso
' iso
Elseif orientation = MAP_ORIENTATION_ISOMETRIC Then
Elseif orientation = MAP_ORIENTATION_ISOMETRIC Then
' TODO: wrapping
' TODO: wrapping
For Local y:Int = 0 Until tl.width + tl.height
For Local y:Int = 0 Until tl.width + tl.height
Local ry:Int = y
Local ry:Int = y
Local rx:Int = 0
Local rx:Int = 0
While ry >= tl.height
While ry >= tl.height
ry -= 1
ry -= 1
rx += 1
rx += 1
Wend
Wend
While ry >= 0 And rx < tl.width
While ry >= 0 And rx < tl.width
Local gid:Int = tl.mapData.cells[rx + ry * tl.mapData.width].gid
Local gid:Int = tl.mapData.cells[rx + ry * tl.mapData.width].gid
If gid > 0 Then
If gid > 0 Then
Local mapTile:TileMapTile = tiles[gid - 1]
Local mapTile:TileMapTile = tiles[gid - 1]
DrawTile(tl, mapTile, (rx - ry - 1) * tileWidth / 2 - bx, (rx + ry + 2) * tileHeight / 2 - mapTile.height - by)
DrawTile(tl, mapTile, (rx - ry - 1) * tileWidth / 2 - bx, (rx + ry + 2) * tileHeight / 2 - mapTile.height - by)
Endif
Endif
ry -= 1
ry -= 1
rx += 1
rx += 1
End
End
Next
Next
End
End
PopMatrix()
PopMatrix()
PostRenderLayer(layer)
PostRenderLayer(layer)
End
End
End
End
' bx,by,bw,bh = render bounds (screen)
' bx,by,bw,bh = render bounds (screen)
' sx,sy = scale x/y (float, defaults to 1) i'll do this later
' sx,sy = scale x/y (float, defaults to 1) i'll do this later
' wx,wy = wrap x/y (boolean, defaults to false)
' wx,wy = wrap x/y (boolean, defaults to false)
Method RenderMap:Void(bx:Int, by:Int, bw:Int, bh:Int, sx:Float = 1, sy:Float = 1, offsetX:Float = 0, offsetY:Float = 0, layerName:String = "ALL", scissor:Bool = True)
Method RenderMap:Void(bx:Int, by:Int, bw:Int, bh:Int, sx:Float = 1, sy:Float = 1, offsetX:Float = 0, offsetY:Float = 0, layerName:String = "ALL", scissor:Bool = True)
PreRenderMap()
PreRenderMap()
If scissor Then
If scissor Then
Local matrix:Float[] = GetMatrix()
Local matrix:Float[] = GetMatrix()
SetScissor(bx * matrix[0] + matrix[4], by * matrix[3] + matrix[5], bw * matrix[0], bh * matrix[3])
SetScissor(bx * matrix[0] + matrix[4], by * matrix[3] + matrix[5], bw * matrix[0], bh * matrix[3])
End If
End If
If layerName = "ALL" Then
If layerName = "ALL" Then
For Local layer:TileMapLayer = EachIn layers
For Local layer:TileMapLayer = EachIn layers
RenderLayer(layer, bx, by, bw, bh, sx, sy, offsetX, offsetY)
RenderLayer(layer, bx, by, bw, bh, sx, sy, offsetX, offsetY)
Next
Next
Else
Else
Local layer:TileMapLayer
Local layer:TileMapLayer
For Local l:TileMapLayer = EachIn layers
For Local l:TileMapLayer = EachIn layers
If l.name.ToUpper() = layerName.ToUpper()
If l.name.ToUpper() = layerName.ToUpper()
layer = l
layer = l
Exit
Exit
End
End
End
End
RenderLayer(layer, bx, by, bw, bh, sx, sy, offsetX, offsetY)
RenderLayer(layer, bx, by, bw, bh, sx, sy, offsetX, offsetY)
End
End
If scissor Then SetScissor(0, 0, DeviceWidth(), DeviceHeight())
If scissor Then SetScissor(0, 0, DeviceWidth(), DeviceHeight())
PostRenderMap()
PostRenderMap()
End
End
Method GetBounds:TileMapRect()
Method GetBounds:TileMapRect()
Local rv:TileMapRect = New TileMapRect
Local rv:TileMapRect = New TileMapRect
If orientation = MAP_ORIENTATION_ORTHOGONAL Then
If orientation = MAP_ORIENTATION_ORTHOGONAL Then
rv.x = 0
rv.x = 0
rv.y = tileHeight - maxTileHeight
rv.y = tileHeight - maxTileHeight
rv.w = (width - 1) * tileWidth + maxTileWidth
rv.w = (width - 1) * tileWidth + maxTileWidth
rv.h = (height - 1) * tileHeight + maxTileHeight
rv.h = (height - 1) * tileHeight + maxTileHeight
Elseif orientation = MAP_ORIENTATION_ISOMETRIC Then
Elseif orientation = MAP_ORIENTATION_ISOMETRIC Then
rv.x = -height * tileWidth / 2
rv.x = -height * tileWidth / 2
rv.y = tileHeight - maxTileHeight
rv.y = tileHeight - maxTileHeight
rv.w = (width - 2) * tileWidth / 2 + maxTileWidth - rv.x
rv.w = (width - 2) * tileWidth / 2 + maxTileWidth - rv.x
rv.h = (width + height) * tileHeight / 2 - rv.y
rv.h = (width + height) * tileHeight / 2 - rv.y
Endif
Endif
Return rv
Return rv
End
End
Method UpdateAnimation:Void(timePassed:Int)
Method UpdateAnimation:Void(timePassed:Int)
Local layer:TileMapLayer, tl:TileMapTileLayer, cell:TileMapCell, t:TileMapTile
Local layer:TileMapLayer, tl:TileMapTileLayer, cell:TileMapCell, t:TileMapTile
Local cellCount:Int, i:Int, j:Int
Local cellCount:Int, i:Int, j:Int
' get the layers as an array
' get the layers as an array
Local layerCount:Int = layers.Length()
Local layerCount:Int = layers.Length()
If layerArray.Length < layerCount Then
If layerArray.Length < layerCount Then
layerArray = layers.ToArray()
layerArray = layers.ToArray()
layerCount = layerArray.Length
layerCount = layerArray.Length
Else
Else
'layerCount = layers.FillArray(layerArray) 'Replaced: See below 3 lines -nobu
'layerCount = layers.FillArray(layerArray) 'Replaced: See below 3 lines -nobu
For Local k:Int = 0 Until layers.Length
For Local k:Int = 0 Until layers.Length
layers.Data[k] = layerArray[k]
layers.Data[k] = layerArray[k]
Next
Next
End
End
' loop on each layer
' loop on each layer
For i = 0 Until layerCount
For i = 0 Until layerCount
' cast
' cast
tl = TileMapTileLayer(layerArray[i])
tl = TileMapTileLayer(layerArray[i])
' if the layer is a tile layer
' if the layer is a tile layer
If tl <> Null Then
If tl <> Null Then
' loop on each cell
' loop on each cell
cellCount = tl.mapData.cells.Length
cellCount = tl.mapData.cells.Length
For j = 0 Until cellCount
For j = 0 Until cellCount
cell = tl.mapData.cells[j]
cell = tl.mapData.cells[j]
' if the cell exists and has a value
' if the cell exists and has a value
If cell <> Null And cell.gid > 0 Then
If cell <> Null And cell.gid > 0 Then
' get the tile
' get the tile
t = tiles[cell.gid-1]
t = tiles[cell.gid-1]
' if the direction is 0 (paused), do nothing
' if the direction is 0 (paused), do nothing
If t <> Null And cell.direction <> 0 Then
If t <> Null And cell.direction <> 0 Then
' add our time to the time passed for the cell
' add our time to the time passed for the cell
cell.timePassed += timePassed
cell.timePassed += timePassed
' if this tile has animation information
' if this tile has animatio
If t.animated Then
' get the new direction if we have one
If t.hasAnimDirection Then cell.direction = t.animDirection
' while it's not paused and we're not up to the current frame
While cell.direction <> 0 And cell.timePassed >= t.animDelay
' move to the next frame
cell.timePassed -= t.animDelay
cell.gid += cell.direction * t.animNext
' get the tile for the new frame
t = tiles[cell.gid-1]
' if there's animation information, get it
If t <> Null And t.animated T