Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FlxTilemap#loadMap(): support Array<Array<Int>> instead of Array<Int>, closes #1290, closes #1324 #1292

Merged
merged 6 commits into from
Oct 12, 2014
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion flixel/system/FlxAssets.hx
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,6 @@ typedef FlxSoundAsset = OneOfThree<String, Sound, Class<Sound>>;
typedef FlxGraphicAsset = OneOfThree<FlxGraphic, BitmapData, String>;
typedef FlxGraphicSource = OneOfThree<BitmapData, Class<Dynamic>, String>;
typedef FlxTilemapGraphicAsset = OneOfFour<FlxTileFrames, FlxGraphic, BitmapData, String>;
typedef FlxTilemapAsset = OneOfTwo<String, Array<Int>>;

private abstract OneOfTwo<T1, T2>(Dynamic) from T1 from T2 to T1 to T2 { }
private abstract OneOfThree<T1, T2, T3>(Dynamic) from T1 from T2 from T3 to T1 to T2 to T3 {}
Expand Down
256 changes: 147 additions & 109 deletions flixel/tile/FlxBaseTilemap.hx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import flixel.FlxObject;
import flixel.math.FlxPoint;
import flixel.math.FlxRandom;
import flixel.math.FlxRect;
import flixel.tile.FlxBaseTilemap.FlxTilemapAutoTiling;
import flixel.util.FlxArrayUtil;
import flixel.system.FlxAssets;
import flixel.group.FlxGroup;
Expand All @@ -16,18 +15,13 @@ class FlxBaseTilemap<Tile:FlxObject> extends FlxObject
* Set this flag to use one of the 16-tile binary auto-tile algorithms (OFF, AUTO, or ALT).
*/
public var auto:FlxTilemapAutoTiling = OFF;
/**
* Read-only variable, do NOT recommend changing after the map is loaded!
*/
public var widthInTiles:Int = 0;
/**
* Read-only variable, do NOT recommend changing after the map is loaded!
*/
public var heightInTiles:Int = 0;
/**
* Read-only variable, do NOT recommend changing after the map is loaded!
*/
public var totalTiles:Int = 0;

public var widthInTiles(default, null):Int = 0;

public var heightInTiles(default, null):Int = 0;

public var totalTiles(default, null):Int = 0;

/**
* Set this to create your own image index remapper, so you can create your own tile layouts.
* Mostly useful in combination with the auto-tilers.
Expand Down Expand Up @@ -156,8 +150,7 @@ class FlxBaseTilemap<Tile:FlxObject> extends FlxObject
/**
* Load the tilemap with string data and a tile graphic.
*
* @param MapData A csv-formatted string indicating what order the tiles should go in (or the path to that file),
* or an Array<Int>. In the latter case YOU MUST SET widthInTiles and heightInTyles manually BEFORE CALLING loadMap()!
* @param MapData A csv-formatted string indicating what order the tiles should go in (or the path to that file)
* @param TileGraphic All the tiles you want to use, arranged in a strip corresponding to the numbers in MapData.
* @param TileWidth The width of your tiles (e.g. 8) - defaults to height of the tile graphic if unspecified.
* @param TileHeight The height of your tiles (e.g. 8) - defaults to width if unspecified.
Expand All @@ -172,9 +165,146 @@ class FlxBaseTilemap<Tile:FlxObject> extends FlxObject
* Can override and customize per-tile-type collision behavior using setTileProperties().
* @return A reference to this instance of FlxTilemap, for chaining as usual :)
*/
public function loadMap(MapData:FlxTilemapAsset, TileGraphic:FlxTilemapGraphicAsset, TileWidth:Int = 0, TileHeight:Int = 0,
public function loadMapFromCSV(MapData:String, TileGraphic:FlxTilemapGraphicAsset, TileWidth:Int = 0, TileHeight:Int = 0,
?AutoTile:FlxTilemapAutoTiling, StartingIndex:Int = 0, DrawIndex:Int = 1, CollideIndex:Int = 1)
{
// path to map data file?
if (Assets.exists(MapData))
{
MapData = Assets.getText(MapData);
}

// Figure out the map dimensions based on the data string
_data = new Array<Int>();
var columns:Array<String>;
var rows:Array<String> = StringTools.trim(cast (MapData, String)).split("\n");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why casting here?

heightInTiles = rows.length;
widthInTiles = 0;
var row:Int = 0;
var column:Int;

while (row < heightInTiles)
{
columns = rows[row++].split(",");

if (columns.length < 1)
{
heightInTiles = heightInTiles - 1;
continue;
}
if (widthInTiles == 0)
{
widthInTiles = columns.length;
}
column = 0;

while (column < widthInTiles)
{
//the current tile to be added:
var curTile:Int = Std.parseInt(columns[column]);

if (curTile < 0)
{
// anything < 0 should be treated as 0 for compatibility with certain map formats (ogmo)
curTile = 0;
}

//if neko, make sure the value was not null, and if it is null,
//make sure it is the last in the row (used to ignore commas)
#if neko
if (curTile != null)
{
_data.push(curTile);
column++;
}
else if (column == columns.length - 1)
{
//if value was a comma, decrease the width by one
widthInTiles--;
}
else
{
//if a non-int value was passed not at the end, warn the user
throw "Value passed wan NaN";
}
#else
//if not neko, dont worry about the comma
_data.push(curTile);
column++;
#end

}
}

loadMapHelper(TileGraphic, TileWidth, TileHeight, AutoTile, StartingIndex, DrawIndex, CollideIndex);
return this;
}

/**
* Load the tilemap with string data and a tile graphic.
*
* @param MapData An array containing the tile indices
* @param WidthInTiles The width of the tilemap in tiles
* @param HeightInTiles The height of the tilemap in tiles
* @param TileGraphic All the tiles you want to use, arranged in a strip corresponding to the numbers in MapData.
* @param TileWidth The width of your tiles (e.g. 8) - defaults to height of the tile graphic if unspecified.
* @param TileHeight The height of your tiles (e.g. 8) - defaults to width if unspecified.
* @param AutoTile Whether to load the map using an automatic tile placement algorithm (requires 16 tiles!).
* Setting this to either AUTO or ALT will override any values you put for StartingIndex, DrawIndex, or CollideIndex.
* @param StartingIndex Used to sort of insert empty tiles in front of the provided graphic.
* Default is 0, usually safest ot leave it at that. Ignored if AutoTile is set.
* @param DrawIndex Initializes all tile objects equal to and after this index as visible.
* Default value is 1. Ignored if AutoTile is set.
* @param CollideIndex Initializes all tile objects equal to and after this index as allowCollisions = ANY.
* Default value is 1. Ignored if AutoTile is set.
* Can override and customize per-tile-type collision behavior using setTileProperties().
* @return A reference to this instance of FlxTilemap, for chaining as usual :)
*/
public function loadMapFromArray(MapData:Array<Int>, WidthInTiles:Int, HeightInTiles:Int, TileGraphic:FlxTilemapGraphicAsset,
TileWidth:Int = 0, TileHeight:Int = 0, ?AutoTile:FlxTilemapAutoTiling, StartingIndex:Int = 0, DrawIndex:Int = 1, CollideIndex:Int = 1)
{
widthInTiles = WidthInTiles;
heightInTiles = HeightInTiles;
_data = cast MapData; // need to cast this to make sure it works in js, can't call copy() on a Dynamic
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again, why casting?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No reason for casting, simply for got to update those lines. Thanks, fixed!

_data = _data.copy(); // make a copy to make sure we don't mess with the original array, which might be used for something!

loadMapHelper(TileGraphic, TileWidth, TileHeight, AutoTile, StartingIndex, DrawIndex, CollideIndex);
return this;
}

/**
* Load the tilemap with string data and a tile graphic.
*
* @param MapData A 2D array containing the tile indices. The length of the inner arrays should be consistent.
* @param TileGraphic All the tiles you want to use, arranged in a strip corresponding to the numbers in MapData.
* @param TileWidth The width of your tiles (e.g. 8) - defaults to height of the tile graphic if unspecified.
* @param TileHeight The height of your tiles (e.g. 8) - defaults to width if unspecified.
* @param AutoTile Whether to load the map using an automatic tile placement algorithm (requires 16 tiles!).
* Setting this to either AUTO or ALT will override any values you put for StartingIndex, DrawIndex, or CollideIndex.
* @param StartingIndex Used to sort of insert empty tiles in front of the provided graphic.
* Default is 0, usually safest ot leave it at that. Ignored if AutoTile is set.
* @param DrawIndex Initializes all tile objects equal to and after this index as visible.
* Default value is 1. Ignored if AutoTile is set.
* @param CollideIndex Initializes all tile objects equal to and after this index as allowCollisions = ANY.
* Default value is 1. Ignored if AutoTile is set.
* Can override and customize per-tile-type collision behavior using setTileProperties().
* @return A reference to this instance of FlxTilemap, for chaining as usual :)
*/
public function loadMapFrom2DArray(MapData:Array<Array<Int>>, TileGraphic:FlxTilemapGraphicAsset, TileWidth:Int = 0, TileHeight:Int = 0,
?AutoTile:FlxTilemapAutoTiling, StartingIndex:Int = 0, DrawIndex:Int = 1, CollideIndex:Int = 1)
{
widthInTiles = MapData[0].length;
heightInTiles = MapData.length;
_data = FlxArrayUtil.flatten2DArray(MapData);

loadMapHelper(TileGraphic, TileWidth, TileHeight, AutoTile, StartingIndex, DrawIndex, CollideIndex);
return this;
}

private function loadMapHelper(TileGraphic:FlxTilemapGraphicAsset, TileWidth:Int = 0, TileHeight:Int = 0, ?AutoTile:FlxTilemapAutoTiling,
StartingIndex:Int = 0, DrawIndex:Int = 1, CollideIndex:Int = 1)
{
totalTiles = _data.length;
auto = (AutoTile == null) ? OFF : AutoTile;
_startingIndex = (StartingIndex <= 0) ? 0 : StartingIndex;

Expand All @@ -185,8 +315,6 @@ class FlxBaseTilemap<Tile:FlxObject> extends FlxObject
CollideIndex = 1;
}

loadMapData(MapData);

_drawIndex = DrawIndex;
_collideIndex = CollideIndex;

Expand All @@ -195,105 +323,15 @@ class FlxBaseTilemap<Tile:FlxObject> extends FlxObject
randomizeIndices();
cacheGraphics(TileWidth, TileHeight, TileGraphic);
postGraphicLoad();

return this;
}

private function postGraphicLoad()
{
initTileObjects();
computeDimensions();
updateMap();
}

private function loadMapData(MapData:FlxTilemapAsset)
{
// Populate data if MapData is a CSV string
if (Std.is(MapData, String))
{
// path to map data file?
if (Assets.exists(MapData))
{
MapData = Assets.getText(MapData);
}

// Figure out the map dimensions based on the data string
_data = new Array<Int>();
var columns:Array<String>;
var rows:Array<String> = StringTools.trim(cast (MapData, String)).split("\n");
heightInTiles = rows.length;
widthInTiles = 0;
var row:Int = 0;
var column:Int;

while (row < heightInTiles)
{
columns = rows[row++].split(",");

if (columns.length < 1)
{
heightInTiles = heightInTiles - 1;
continue;
}
if (widthInTiles == 0)
{
widthInTiles = columns.length;
}
column = 0;

while (column < widthInTiles)
{
//the current tile to be added:
var curTile:Int = Std.parseInt(columns[column]);

if (curTile < 0)
{
// anything < 0 should be treated as 0 for compatibility with certain map formats (ogmo)
curTile = 0;
}

//if neko, make sure the value was not null, and if it is null,
//make sure it is the last in the row (used to ignore commas)
#if neko
if (curTile != null)
{
_data.push(curTile);
column++;
}
else if (column == columns.length - 1)
{
//if value was a comma, decrease the width by one
widthInTiles--;
}
else
{
//if a non-int value was passed not at the end, warn the user
throw "Value passed wan NaN";
}
#else
//if not neko, dont worry about the comma
_data.push(curTile);
column++;
#end

}
}
}
// Data is already set up as an Array<Int>
// DON'T FORGET TO SET 'widthInTiles' and 'heightInTiles' manually BEFORE CALLING loadMap() if you pass an Array<Int>!
else if (Std.is(MapData, Array))
{
_data = cast MapData; // need to cast this to make sure it works in js, can't call copy() on a Dynamic
_data = _data.copy(); // make a copy to make sure we don't mess with the original array, which might be used for something!
}
else
{
throw "Unexpected MapData format '" + Type.typeof(MapData) + "' passed into loadMap. Map data must be CSV string or Array<Int>.";
}

totalTiles = _data.length;
}

private function applyAutoTile():Void
{
// Pre-process the map data if it's auto-tiled
Expand Down
1 change: 0 additions & 1 deletion flixel/tile/FlxTilemap.hx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import flixel.math.FlxMath;
import flixel.math.FlxMatrix;
import flixel.math.FlxPoint;
import flixel.system.FlxAssets.FlxGraphicAsset;
import flixel.system.FlxAssets.FlxTilemapAsset;
import flixel.system.FlxAssets.FlxTilemapGraphicAsset;
import flixel.tile.FlxBaseTilemap.FlxTilemapAutoTiling;
import flixel.util.FlxArrayUtil;
Expand Down
16 changes: 16 additions & 0 deletions flixel/util/FlxArrayUtil.hx
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,20 @@ class FlxArrayUtil
}
}
}

/**
* Flattens 2D arrays into 1D arrays.
*/
@:generic
public static function flatten2DArray<T>(array:Array<Array<T>>):Array<T>
{
var result = [];

for (innerArray in array)
{
result = result.concat(innerArray);
}

return result;
}
}
2 changes: 2 additions & 0 deletions tests/src/TestSuite.hx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import flixel.tile.FlxTilemapTest;
import flixel.tweens.FlxTweenTest;
import flixel.tweens.motion.LinearMotionTest;
import flixel.ui.FlxButtonTest;
import flixel.util.FlxArrayUtilTest;
import flixel.util.FlxColorTest;
import flixel.util.FlxGradientTest;
import flixel.util.FlxPathTest;
Expand Down Expand Up @@ -66,6 +67,7 @@ class TestSuite extends massive.munit.TestSuite
add(flixel.tweens.FlxTweenTest);
add(flixel.tweens.motion.LinearMotionTest);
add(flixel.ui.FlxButtonTest);
add(flixel.util.FlxArrayUtilTest);
add(flixel.util.FlxColorTest);
add(flixel.util.FlxGradientTest);
add(flixel.util.FlxPathTest);
Expand Down
2 changes: 1 addition & 1 deletion tests/src/flixel/FlxObjectTest.hx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class FlxObjectTest extends FlxTest
@Test
function testVelocityCollidingWithTilemap()
{
tilemap.loadMap("1, 1, 1, 1, 1, 1, 1", FlxGraphic.fromClass(GraphicAuto));
tilemap.loadMapFromCSV("1, 1, 1, 1, 1, 1, 1", FlxGraphic.fromClass(GraphicAuto));
velocityColldingWith(tilemap);
}

Expand Down
Loading