Skip to content
Open
21 changes: 21 additions & 0 deletions com/haxepunk/tmx/TmxCollisionObject.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.haxepunk.tmx;

import com.haxepunk.tmx.TmxVec4;

/**
* ...
* @author Jero
*/
class TmxCollisionObject extends TmxVec4
{
public var type:String;
public var radius:Int;
public var polyPoints:Array<Float>;
public function new(x:Float, y:Float, width:Float, height:Float, type:String = "box", radius:Int = 0, polyPoints:Array<Float> = null)
{
this.type = type;
this.radius = radius;
this.polyPoints = polyPoints;
super(x, y, width, height);
}
}
178 changes: 169 additions & 9 deletions com/haxepunk/tmx/TmxEntity.hx
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,28 @@ import com.haxepunk.masks.Grid;
import com.haxepunk.masks.SlopedGrid;
import com.haxepunk.masks.Masklist;
import com.haxepunk.tmx.TmxMap;
import com.haxepunk.tmx.TmxTileSet;
import com.haxepunk.tmx.TmxCollisionObject;
import com.haxepunk.masks.Circle;
import com.haxepunk.masks.Hitbox;
import com.haxepunk.masks.Polygon;
import flash.geom.Rectangle;
import com.haxepunk.graphics.atlas.TileAtlas;

private abstract Map(TmxMap)

private abstract TmxMapData(TmxMap)
{
private inline function new(map:TmxMap) this = map;
@:to public inline function toMap():TmxMap return this;

@:from public static inline function fromString(s:String)
return new Map(new TmxMap(Xml.parse(openfl.Assets.getText(s))));
return new TmxMapData(new TmxMap(Xml.parse(openfl.Assets.getText(s))));

@:from public static inline function fromTmxMap(map:TmxMap)
return new Map(map);
return new TmxMapData(map);

@:from public static inline function fromMapData(mapData:MapData)
return new Map(new TmxMap(mapData));
return new TmxMapData(new TmxMap(mapData));
}

class TmxEntity extends Entity
Expand All @@ -31,7 +39,7 @@ class TmxEntity extends Entity
public var map:TmxMap;
public var debugObjectMask:Bool;

public function new(mapData:Map)
public function new(mapData:TmxMapData)
{
super();

Expand Down Expand Up @@ -88,6 +96,158 @@ class TmxEntity extends Entity
}
}

/**
* Loads all graphics for the layers in layerNames and, optionally, loads collision information from tiles and sets masks with that
* @param layerNames layers you want to show
* @param skip gid of tiles that should be skipped.
* @param collideLayer the name of the layer to collide with. (ignored if addTileMask = false)
* @param addTileMask if we should process tile collision information and generate a mask.
* @param typeName the type to set for masks.
*/
public function loadGraphics(layerNames:Array<String>, skip:Array<Int> = null, collideLayer:String = "collide", addTileMask:Bool = false, typeName:String = "solid"):Void
{
var gid:Int;
var layer:TmxLayer;
var ml:Masklist = null;
var tilesCollisions:Array<TmxCollisionObject> = new Array<TmxCollisionObject>();
var tileMaps:TmxOrderedHash<TmxTilemap> = new TmxOrderedHash<TmxTilemap>();

for (name in layerNames)
{
if (map.layers.exists(name) == false)
{
#if debug
trace("Layer '" + name + "' doesn't exist");
#end
continue;
}
layer = map.layers.get(name);
if (!layer.visible)
{
#if debug
trace("Layer '" + name + "' is not visible.");
#end
continue;
}
for (row in 0...layer.height)
{
for (col in 0...layer.width)
{
gid = layer.tileGIDs[row][col];
if (gid < 0) continue;
var set = map.getGidOwner(gid);
if (set == null)
continue;
gid -= set.firstGID;

if (gid < 0) continue;

if (!tileMaps.exists( name + "_" + set.name))
{
#if flash
var _tileset = set.image;
#else
var _tileset = new TileAtlas(set.image);
#end
var tm:TmxTilemap = new TmxTilemap(_tileset, map.fullWidth, map.fullHeight, map.tileWidth, map.tileHeight, set.spacing, set.spacing, set.offsetX, set.offsetY);
tileMaps.set(name + "_" + set.name, tm);
}

if (skip == null || Lambda.has(skip, gid) == false)
{
if (addTileMask && name == collideLayer)
{
var tileMask:Array<TmxCollisionObject> = set.getCollisionsByGid(gid);
if (tileMask != null && tileMask.length > 0)
{
var rect:Rectangle = new Rectangle(x + (col * set.tileWidth), y + (row * set.tileHeight), set.tileWidth, set.tileHeight);
for (colObj in tileMask)
{
var _colObj:TmxCollisionObject = new TmxCollisionObject(colObj.x + rect.x, colObj.y + rect.y, colObj.width, colObj.height, colObj.type, colObj.radius, colObj.polyPoints);
if (_colObj.type == "poly")
{
var pArr:Array<Float> = new Array<Float>();
var even:Bool = true;
for (p in _colObj.polyPoints)
{
pArr.push(p + (even ? rect.x : rect.y));
even = !even;
}
_colObj.polyPoints = pArr;
}
tilesCollisions.push(_colObj);
}
}
else
{
#if debug
trace("You have a tile in layer " + name + " with id: " + gid + " that has no collision setup");
#end
}
}
tileMaps.get(name + "_" + set.name).setTile(col, row, gid);
}
}
}
for (tm in tileMaps)
{
addGraphic(tm);
}
}
if (addTileMask && tilesCollisions.length > 0)
{
var co:TmxCollisionObject;
var masks:Array<Mask> = new Array<Mask>();
for (co in tilesCollisions)
{
switch (co.type)
{
case "circle":
masks.push(new Circle(co.radius, Std.int(co.x), Std.int(co.y)));
#if debug
trace("Adding circle mask");
if (debugObjectMask)
{
var c = Image.createCircle(co.radius, 0xFF0000, 0.5);
c.x = Std.int(co.x);
c.y = Std.int(co.y);
addGraphic(c);
}
#end
case "poly":
var p:Polygon = Polygon.createFromArray(co.polyPoints);
p.x = 0;
p.y = 0;
masks.push(p);
#if debug
trace("Adding poly mask");
if (debugObjectMask)
{
var i:Image = Image.createPolygon(p, 0xFF0000, 0.5);
addGraphic(i);
}
#end
case "box":
masks.push( new Hitbox(Std.int(co.width), Std.int(co.height), Std.int(co.x), Std.int(co.y)));
#if debug
trace("Adding box mask");
if (debugObjectMask)
{
var i:Image = Image.createRect(Std.int(co.width), Std.int(co.height), 0xFF0000, 0.5);
i.x = Std.int(co.x);
i.y = Std.int(co.y);
addGraphic(i);
}
#end
}
}
ml = new Masklist(masks);
mask = ml;
this.type = typeName;
setHitbox(map.fullWidth, map.fullHeight);
}
}

public function loadMask(collideLayer:String = "collide", typeName:String = "solid", skip:Array<Int> = null)
{
var tileCoords:Array<TmxVec4> = new Array<TmxVec4>();
Expand Down Expand Up @@ -123,7 +283,7 @@ class TmxEntity extends Entity
setHitbox(grid.width, grid.height);
return tileCoords;
}

public function loadSlopedMask(collideLayer:String = "collide", typeName:String = "solid", skip:Array<Int> = null)
{
if (!map.layers.exists(collideLayer))
Expand All @@ -133,12 +293,12 @@ class TmxEntity extends Entity
#end
return;
}

var gid:Int;
var layer:TmxLayer = map.layers.get(collideLayer);
var grid = new SlopedGrid(map.fullWidth, map.fullHeight, map.tileWidth, map.tileHeight);
var types = Type.getEnumConstructs(TileType);

for (row in 0...layer.height)
{
for (col in 0...layer.width)
Expand Down Expand Up @@ -170,7 +330,7 @@ class TmxEntity extends Entity
}
}
}

this.mask = grid;
this.type = typeName;
setHitbox(grid.width, grid.height);
Expand Down
42 changes: 21 additions & 21 deletions com/haxepunk/tmx/TmxLayer.hx
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,24 @@ class TmxLayer
public var visible:Bool;
public var tileGIDs:Array<Array<Int>>;
public var properties:TmxPropertySet;

public function new(source:Fast, parent:TmxMap)
{
properties = new TmxPropertySet();
map = parent;
name = source.att.name;
x = (source.has.x) ? Std.parseInt(source.att.x) : 0;
y = (source.has.y) ? Std.parseInt(source.att.y) : 0;
width = Std.parseInt(source.att.width);
height = Std.parseInt(source.att.height);
visible = (source.has.visible && source.att.visible == "1") ? true : false;
width = Std.parseInt(source.att.width);
height = Std.parseInt(source.att.height);
visible = (source.has.visible && source.att.visible == "1") || !source.has.visible ? true : false;
opacity = (source.has.opacity) ? Std.parseFloat(source.att.opacity) : 0;

//load properties
var node:Fast;
for (node in source.nodes.properties)
properties.extend(node);

//load tile GIDs
tileGIDs = [];
var data:Fast = source.node.data;
Expand Down Expand Up @@ -87,7 +87,7 @@ class TmxLayer
}
}
}

public function toCsv(tileSet:TmxTileSet = null):String
{
var max:Int = 0xFFFFFF;
Expand All @@ -113,7 +113,7 @@ class TmxLayer
}
return result;
}

/* ONE DIMENSION ARRAY
public static function arrayToCSV(input:Array, lineWidth:Int):String
{
Expand All @@ -131,7 +131,7 @@ class TmxLayer
return result;
}
*/

private static function csvToArray(input:String):Array<Array<Int>>
{
var result:Array<Array<Int>> = new Array<Array<Int>>();
Expand All @@ -149,7 +149,7 @@ class TmxLayer
}
return result;
}

private static function base64ToArray(chunk:String, lineWidth:Int, compressed:Bool):Array<Array<Int>>
{
var result:Array<Array<Int>> = new Array<Array<Int>>();
Expand All @@ -158,11 +158,11 @@ class TmxLayer
{
#if (js && !format)
throw "Need the format library to use compressed map on html5";
#else
#else
data.uncompress();
#end
}

data.endian = Endian.LITTLE_ENDIAN;
while(data.position < data.length)
{
Expand All @@ -174,10 +174,10 @@ class TmxLayer
}
return result;
}

private static inline var BASE64_CHARS:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
private static function base64ToByteArray(data:String):ByteArray

private static function base64ToByteArray(data:String):ByteArray
{
var output:ByteArray = new ByteArray();
//initialize lookup table
Expand All @@ -187,33 +187,33 @@ class TmxLayer
{
lookup[BASE64_CHARS.charCodeAt(c)] = c;
}

var i:Int = 0;
while (i < data.length - 3)
while (i < data.length - 3)
{
// Ignore whitespace
if (data.charAt(i) == " " || data.charAt(i) == "\n")
{
i++; continue;
}

//read 4 bytes and look them up in the table
var a0:Int = lookup[data.charCodeAt(i)];
var a1:Int = lookup[data.charCodeAt(i + 1)];
var a2:Int = lookup[data.charCodeAt(i + 2)];
var a3:Int = lookup[data.charCodeAt(i + 3)];

// convert to and write 3 bytes
if(a1 < 64)
output.writeByte((a0 << 2) + ((a1 & 0x30) >> 4));
if(a2 < 64)
output.writeByte(((a1 & 0x0f) << 4) + ((a2 & 0x3c) >> 2));
if(a3 < 64)
output.writeByte(((a2 & 0x03) << 6) + a3);

i += 4;
}

// Rewind & return decoded data
output.position = 0;
return output;
Expand Down
Loading