using SFML.Graphics;
using SFML.System;
using SFML.Window;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
namespace Otter {
///
/// Graphic used for loading and rendering a tilemap. Renders tiles using a vertex array.
///
public class Tilemap : Graphic {
#region Public Properties
///
/// The width in pixels of each tile.
///
public int TileWidth { get; private set; }
///
/// The height in pixels of each tile.
///
public int TileHeight { get; private set; }
///
/// The number of rows in the entire tilemap.
///
public int TileRows { get; private set; }
///
/// The number of columsn in the entire tilemap.
///
public int TileColumns { get; private set; }
///
/// The tile layers to render.
///
public SortedDictionary> TileLayers { get; private set; }
#endregion
#region Public Fields
///
/// Determines if the X and Y positions of tiles are interpreted as pixels or tile coords.
///
public bool UsePositions;
///
/// The default layer name to use.
///
public string DefaultLayerName = "base";
#endregion
#region Private Fields
Dictionary layerNames = new Dictionary();
Dictionary>> tileTable = new Dictionary>>();
Dictionary> autoTileTable;
#region Auto Tile Data
string autoTileDefaultData = @"0:
? 1 ?
0 x 0
? 0 ?
=
1:
? 0 ?
0 x 1
? 0 ?
=
2:
? 0 ?
0 x 0
? 1 ?
=
3:
? 0 ?
1 x 0
? 0 ?
=
4:
? 1 0
0 x 1
? 0 ?
=
5:
? 0 ?
0 x 1
? 1 0
=
6:
? 0 ?
1 x 0
0 1 ?
=
7:
0 1 ?
1 x 0
? 0 ?
=
8:
? 1 1
0 x 1
? 0 ?
=
9:
? 0 ?
0 x 1
? 1 1
=
10:
? 0 ?
1 x 0
1 1 ?
=
11:
1 1 ?
1 x 0
? 0 ?
=
12:
? 1 0
0 x 1
? 1 0
=
13:
? 0 ?
1 x 1
0 1 0
=
14:
0 1 ?
1 x 0
0 1 ?
=
15:
0 1 0
1 x 1
? 0 ?
=
16:
? 1 1
0 x 1
? 1 0
=
17:
? 1 0
0 x 1
? 1 1
=
18:
? 1 1
0 x 1
? 1 1
=
19:
? 0 ?
1 x 1
0 1 1
=
20:
? 0 ?
1 x 1
1 1 0
=
21:
? 0 ?
1 x 1
1 1 1
=
22:
0 1 ?
1 x 0
1 1 ?
=
23:
1 1 ?
1 x 0
0 1 ?
=
24:
1 1 ?
1 x 0
1 1 ?
=
25:
0 1 1
1 x 1
? 0 ?
=
26:
1 1 0
1 x 1
? 0 ?
=
27:
1 1 1
1 x 1
? 0 ?
=
28:
0 1 0
1 x 1
0 1 0
=
29:
0 1 1
1 x 1
0 1 0
=
30:
0 1 0
1 x 1
0 1 1
=
31:
0 1 0
1 x 1
1 1 0
=
32:
1 1 0
1 x 1
0 1 0
=
33:
0 1 1
1 x 1
0 1 1
=
34:
0 1 0
1 x 1
1 1 1
=
35:
1 1 0
1 x 1
1 1 0
=
36:
1 1 1
1 x 1
0 1 0
=
37:
0 1 1
1 x 1
1 1 0
=
38:
1 1 0
1 x 1
0 1 1
=
39:
0 1 1
1 x 1
1 1 1
=
40:
1 1 1
1 x 1
0 1 1
=
41:
1 1 1
1 x 1
1 1 0
=
42:
1 1 0
1 x 1
1 1 1
=
43:
1 1 1
1 x 1
1 1 1
=
44:
? 0 ?
0 x 0
? 0 ?
=
45:
? 1 ?
0 x 0
? 1 ?
=
46:
? 0 ?
1 x 1
? 0 ?";
#endregion
int
sourceColumns,
sourceRows;
#endregion
#region Constructors
///
/// Create a new Tilemap using the path of a texture.
///
/// The file path to the texture to use.
/// The width of the Tilemap in pixels.
/// The height of the Tilemap in pixels.
/// The width of each tile in pixels.
/// The height of each tile in pixels.
public Tilemap(string source, int width, int height, int tileWidth, int tileHeight) : base() {
SetTexture(new Texture(source));
Initialize(width, height, tileWidth, tileHeight);
}
///
/// Create a new Tilemap using the path of a texture.
///
/// The file path to the texture to use.
/// The width and height of the Tilemap in pixels.
/// The width and height of each tile in pixels.
public Tilemap(string source, int size, int tileSize) : this(source, size, size, tileSize, tileSize) { }
///
/// Create a new Tilemap using a Texture.
///
/// The Texture to use.
/// The width of the Tilemap in pixels.
/// The height of the Tilemap in pixels.
/// The width of each tile in pixels.
/// The height of each tile in pixels.
public Tilemap(Texture texture, int width, int height, int tileWidth, int tileHeight) : base() {
SetTexture(texture);
Initialize(width, height, tileWidth, tileHeight);
}
///
/// Create a new Tilemap using a Texture.
///
/// The Texture to use.
/// The width and height of the Tilemap in pixels.
/// The width and height of each tile in pixels.
public Tilemap(Texture texture, int size, int tileSize) : this(texture, size, size, tileSize, tileSize) { }
///
/// Create a new Tilemap using an AtlasTexture.
///
/// The AtlasTexture to use.
/// The width of the Tilemap in pixels.
/// The height of the Tilemap in pixels.
/// The width of each tile in pixels.
/// The height of each tile in pixels.
public Tilemap(AtlasTexture texture, int width, int height, int tileWidth, int tileHeight) {
SetTexture(texture);
Initialize(width, height, tileWidth, tileHeight);
}
///
/// Create a new Tilemap using an AtlasTexture.
///
/// The AtlasTexture to use.
/// The width and height of the Tilemap in pixels.
/// The width and height of each tile in pixels.
public Tilemap(AtlasTexture texture, int size, int tileSize) : this(texture, size, size, tileSize, tileSize) { }
///
/// Create a new Tilemap without any texture. Tiles will be solid colors instead.
///
/// The width of the Tilemap in pixels.
/// The height of the Tilemap in pixels.
/// The width of each tile in pixels.
/// The height of each tile in pixels.
public Tilemap(int width, int height, int tileWidth, int tileHeight) {
Initialize(width, height, tileWidth, tileHeight);
}
///
/// Create a new Tilemap without any texture. Tiles will be solid colors instead.
///
/// The width and height of the Tilemap in pixels.
/// The width and height of each tile in pixels.
public Tilemap(int size, int tileSize) : this(size, size, tileSize, tileSize) { }
#endregion
#region Private Methods
void Initialize(int width, int height, int tileWidth, int tileHeight) {
if (width < 0) throw new ArgumentOutOfRangeException("Width must be greater than 0.");
if (height < 0) throw new ArgumentOutOfRangeException("Height must be greater than 0.");
TileLayers = new SortedDictionary>();
AddLayer(DefaultLayerName);
TileWidth = tileWidth;
TileHeight = tileHeight;
TileColumns = (int)Util.Ceil((float)width / tileWidth);
TileRows = (int)Util.Ceil((float)height / tileHeight);
sourceColumns = (int)(TextureRegion.Width / tileWidth);
sourceRows = (int)(TextureRegion.Height / tileHeight);
Width = width;
Height = height;
}
protected override void UpdateDrawable() {
base.UpdateDrawable();
SFMLVertices.Clear();
foreach (var layer in TileLayers.Reverse()) {
//for (int i = TileLayers.Count - 1; i >= 0; i--) {
// var layer = TileLayers.Values[i];
foreach (var tile in layer.Value) {
//tile.Alpha = Alpha;
tile.tilemapColor.R = Color.R;
tile.tilemapColor.G = Color.G;
tile.tilemapColor.B = Color.B;
tile.tilemapColor.A = Color.A;
tile.AppendVertices(SFMLVertices);
}
}
}
void RegisterTile(int x, int y, int layer, TileInfo tile) {
if (!tileTable.ContainsKey(layer)) {
tileTable.Add(layer, new Dictionary>());
}
if (!tileTable[layer].ContainsKey(x)) {
tileTable[layer].Add(x, new Dictionary());
}
tileTable[layer][x].Add(y, tile);
}
void RemoveTile(int x, int y, int layer) {
if (tileTable.ContainsKey(layer)) {
if (tileTable[layer].ContainsKey(x)) {
if (tileTable[layer][x].ContainsKey(y)) {
tileTable[layer][x].Remove(y);
}
}
}
}
#endregion
#region Public Methods
///
/// Set a tile to a specific color.
///
/// The tile's x position on the map.
/// The tile's y position on the map.
/// The tile's color.
/// The tile's layer.
/// The TileInfo of the altered tile.
public TileInfo SetTile(int tileX, int tileY, Color color, string layer = "") {
if (layer == "") layer = DefaultLayerName;
// Clear the tile there first so tiles do not stack.
ClearTile(tileX, tileY, layer);
// Update arguments after calling other tile methods.
if (!UsePositions) {
tileX *= TileWidth;
tileY *= TileHeight;
}
// Clamp tile inside tilemap.
tileX = (int)Util.Clamp(tileX, 0, Width - TileWidth);
tileY = (int)Util.Clamp(tileY, 0, Height - TileHeight);
var t = new TileInfo(tileX, tileY, -1, -1, TileWidth, TileHeight, color);
TileLayers[layerNames[layer]].Add(t);
// Register tile for look ups.
RegisterTile(tileX, tileY, layerNames[layer], t);
NeedsUpdate = true;
return t;
}
///
/// Set a tile to a specific color.
///
/// The tile's x position on the map.
/// The tile's y position on the map.
/// The tile's color.
/// The tile's layer.
/// The TileInfo of the altered tile.
public TileInfo SetTile(int tileX, int tileY, Color color, Enum layer) {
return SetTile(tileX, tileY, color, Util.EnumValueToString(layer));
}
///
/// Set a tile to a specific tile from the source texture.
///
/// The tile's X position on the map.
/// The tile's Y position on the map.
/// The source X position from the tile map in pixels.
/// The source Y position from the tile map in pixels.
/// The tile's layer.
/// The TileInfo for the altered tile.
public TileInfo SetTile(int tileX, int tileY, int sourceX, int sourceY, string layer = "") {
sourceX += TextureLeft;
sourceY += TextureTop;
if (layer == "") layer = DefaultLayerName;
// Clear the tile there first so tiles do not stack.
ClearTile(tileX, tileY, layer);
// Update arguments after calling other tile methods.
if (!UsePositions) {
tileX *= TileWidth;
tileY *= TileHeight;
}
tileX = (int)Util.Clamp(tileX, 0, Width - TileWidth);
tileY = (int)Util.Clamp(tileY, 0, Height - TileHeight);
var t = new TileInfo(tileX, tileY, sourceX, sourceY, TileWidth, TileHeight);
TileLayers[layerNames[layer]].Add(t);
RegisterTile(tileX, tileY, layerNames[layer], t);
NeedsUpdate = true;
return t;
}
///
/// Set a tile to a specific tile from the source texture.
///
/// The tile's X position on the map.
/// The tile's Y position on the map.
/// The source X position from the tile map in pixels.
/// The source Y position from the tile map in pixels.
/// The tile's layer.
/// The TileInfo for the altered tile.
public TileInfo SetTile(int tileX, int tileY, int sourceX, int sourceY, Enum layer) {
return SetTile(tileX, tileY, sourceX, sourceY, Util.EnumValueToString(layer));
}
///
/// Load tile data from an XmlElement.
///
/// An XmlElement containing attributes x, y, tx, and ty.
/// The TileInfo for the loaded tile.
public TileInfo SetTile(XmlElement e) {
int x, y, tx, ty;
if (UsePositions) {
x = e.AttributeInt("x") * TileWidth;
y = e.AttributeInt("y") * TileHeight;
}
else {
x = e.AttributeInt("x");
y = e.AttributeInt("y");
}
tx = e.AttributeInt("tx") * TileWidth;
ty = e.AttributeInt("ty") * TileHeight;
return SetTile(x, y, tx, ty);
}
///
/// Set a tile on the Tilemap to a specific tile.
///
/// The X position of the tile to change.
/// The Y position of the tile to change.
/// The index of the tile to change to.
///
/// The TileInfo from the altered tile.
public TileInfo SetTile(int tileX, int tileY, int tileIndex, string layer = "") {
int sourceX = (int)(Util.TwoDeeX((int)tileIndex, (int)sourceColumns) * TileWidth);
int sourceY = (int)(Util.TwoDeeY((int)tileIndex, (int)sourceColumns) * TileHeight);
return SetTile(tileX, tileY, sourceX, sourceY, layer);
}
///
/// Set a tile on the Tilemap to a specific tile.
///
/// The X position of the tile to change.
/// The Y position of the tile to change.
/// The index of the tile to change to.
/// The TileInfo from the altered tile.
public TileInfo SetTile(int tileX, int tileY, int tileIndex, Enum layer) {
return SetTile(tileX, tileY, tileIndex, Util.EnumValueToString(layer));
}
///
/// Set a tile on the Tilemap to be flipped horizontally and/or vertically.
///
/// The X position of the tile to change.
/// The Y position of the tile to change.
/// Whether the tile should be horizontally flipped.
/// Whether the tile should be vertically flipped.
/// The TileInfo from the altered tile.
public TileInfo SetTile(int tileX, int tileY, bool flipX, bool flipY)
{
GetTile(tileX, tileY).FlipX = flipX;
GetTile(tileX, tileY).FlipY = flipY;
return GetTile(tileX, tileY);
}
///
/// Set a rectangle area of tiles to a defined color.
///
/// The X position of the tile to change.
/// The Y position of the tile to change.
/// The width of tiles to change.
/// The height of tiles to change.
/// The color to change the colors to.
/// The layer to place the tiles on.
public void SetRect(int tileX, int tileY, int tileWidth, int tileHeight, Color color, string layer = "") {
for (int xx = tileX; xx < tileX + tileWidth; xx++) {
for (int yy = tileY; yy < tileY + tileHeight; yy++) {
SetTile(xx, yy, color, layer);
}
}
}
///
/// Set a rectangle area of tiles to a defined color.
///
/// The X position of the tile to change.
/// The Y position of the tile to change.
/// The width of tiles to change.
/// The height of tiles to change.
/// The color to change the colors to.
/// The layer to place the tiles on.
public void SetRect(int tileX, int tileY, int tileWidth, int tileHeight, Color color, Enum layer) {
SetRect(tileX, tileY, tileWidth, tileHeight, color, Util.EnumValueToString(layer));
}
///
/// Set a rectangle of tiles to a tile defined by texture coordinates.
///
/// The X position of the rectangle to change.
/// The Y position of the rectangle to change.
/// The width of tiles to change.
/// The height of tiles to change.
/// The X position in the source Texture to use to draw the tiles.
/// The Y position in the source Texture to use to draw the tiles.
/// The layer to place the tiles on.
public void SetRect(int tileX, int tileY, int tileWidth, int tileHeight, int sourceX, int sourceY, string layer = "") {
for (int xx = tileX; xx < tileX + tileWidth; xx++) {
for (int yy = tileY; yy < tileY + tileHeight; yy++) {
SetTile(xx, yy, sourceX, sourceY, layer);
}
}
}
///
/// Set a rectangle of tiles to a tile defined by texture coordinates.
///
/// The X position of the rectangle to change.
/// The Y position of the rectangle to change.
/// The width of tiles to change.
/// The height of tiles to change.
/// The X position in the source Texture to use to draw the tiles.
/// The Y position in the source Texture to use to draw the tiles.
/// The layer to place the tiles on.
public void SetRect(int tileX, int tileY, int tileWidth, int tileHeight, int sourceX, int sourceY, Enum layer) {
SetRect(tileX, tileY, tileWidth, tileHeight, sourceX, sourceY, Util.EnumValueToString(layer));
}
///
/// Set a rectangle of tiles to a tile defined by an index.
///
/// The X position of the rectangle to change.
/// The Y position of the rectangle to change.
/// The width of tiles to change.
/// The height of tiles to change.
/// The index of the tile to change the tiles to.
/// The layer to place the tiles on.
public void SetRect(int tileX, int tileY, int tileWidth, int tileHeight, int tileIndex, string layer = "") {
for (int xx = tileX; xx < tileX + tileWidth; xx++) {
for (int yy = tileY; yy < tileY + tileHeight; yy++) {
SetTile(xx, yy, tileIndex, layer);
}
}
}
///
/// Set a rectangle of tiles to a tile defined by an index.
///
/// The X position of the rectangle to change.
/// The Y position of the rectangle to change.
/// The width of tiles to change.
/// The height of tiles to change.
/// The index of the tile to change the tiles to.
/// The layer to place the tiles on.
public void SetRect(int tileX, int tileY, int tileWidth, int tileHeight, int tileIndex, Enum layer) {
SetRect(tileX, tileY, tileWidth, tileHeight, tileIndex, Util.EnumValueToString(layer));
}
///
/// Set all tiles of a specific layer.
///
/// The index of the tile to change the tiles to.
/// The layer to change.
public void SetLayer(int tileIndex, string layer = "") {
if (layer == "") layer = DefaultLayerName;
SetRect(0, 0, TileColumns, TileRows, tileIndex, layer);
}
///
/// Set all tiles of a specific layer.
///
/// The X position in the source Texture to use to draw the tiles.
/// The Y position in the source Texture to use to draw the tiles.
/// The layer to change.
public void SetLayer(int sourceX, int sourceY, string layer = "") {
if (layer == "") layer = DefaultLayerName;
SetRect(0, 0, TileColumns, TileRows, sourceX, sourceY, layer);
}
///
/// Set all tiles of a specific layer.
///
/// The color to change the tile to.
/// The layer to change.
public void SetLayer(Color color, string layer = "") {
if (layer == "") layer = DefaultLayerName;
SetRect(0, 0, TileColumns, TileRows, color, layer);
}
///
/// Set all tiles of a specific layer.
///
/// The index of the tile to change the tiles to.
/// The layer to change.
public void SetLayer(int tileIndex, Enum layer) {
SetLayer(tileIndex, Util.EnumValueToString(layer));
}
///
/// Set all tiles of a specific layer.
///
/// The X position in the source Texture to use to draw the tiles.
/// The Y position in the source Texture to use to draw the tiles.
/// The layer to change.
public void SetLayer(int sourceX, int sourceY, Enum layer) {
SetLayer(sourceX, sourceY, Util.EnumValueToString(layer));
}
///
/// Set all tiles of a specific layer.
///
/// The color to change the tile to.
/// The layer to change.
public void SetLayer(Color color, Enum layer) {
SetLayer(color, Util.EnumValueToString(layer));
}
///
/// Get the TileInfo of a specific tile on the tilemap.
///
/// The X position of the tile to retrieve.
/// The Y position of the tile to retrieve.
/// The layer to search through for the tile.
/// The TileInfo for the found tile.
public TileInfo GetTile(int tileX, int tileY, string layer = "") {
if (layer == "") layer = DefaultLayerName;
if (!UsePositions) {
tileX *= TileWidth;
tileY *= TileHeight;
}
tileX = (int)Util.Clamp(tileX, 0, Width - TileWidth);
tileY = (int)Util.Clamp(tileY, 0, Height - TileHeight);
var layerDepth = layerNames[layer];
if (!tileTable.ContainsKey(layerDepth)) {
return null;
}
if (!tileTable[layerDepth].ContainsKey(tileX)) {
return null;
}
if (!tileTable[layerDepth][tileX].ContainsKey(tileY)) {
return null;
}
return tileTable[layerDepth][tileX][tileY];
}
///
/// Get the TileInfo of a specific tile on the tilemap.
///
/// The X position of the tile to retrieve.
/// The Y position of the tile to retrieve.
/// The layer to search through for the tile.
/// The TileInfo for the found tile.
public TileInfo GetTile(int tileX, int tileY, Enum layer) {
return GetTile(tileX, tileY, Util.EnumValueToString(layer));
}
///
/// Load tiles in from a GridCollider.
///
/// The GridCollider to reference.
/// The color to set tiles that are collidable on the grid.
/// The layer to place the tiles on.
public void LoadGrid(GridCollider grid, Color color, string layer = "") {
for (var i = 0; i < grid.TileColumns; i++) {
for (var j = 0; j < grid.TileRows; j++) {
if (grid.GetTile(i, j)) {
SetTile(i, j, color, layer);
}
}
}
}
///
/// Assign the tile data to use for LoadGridAutoTile.
///
/// The tile data file.
public void SetAutoTileData(string tileData) {
// Parse tile data
autoTileTable = new Dictionary>();
var dataSplit = tileData.Split('=');
var tileValues = new List() {
128, 1, 16, 8, 0, 2, 64, 4, 32
};
var tileNumber = 0;
foreach (var d in dataSplit) {
var split = d.Split(':');
var tileListString = split[0].ClearWhitespace();
var neighborString = split[1].ClearWhitespace();
var tileList = new List();
foreach (var t in tileListString.Split(',')) {
tileList.Add(int.Parse(t));
}
// find all the 1s, and add those up and put it as the first entry
int tileValue = 0;
var i = 0;
foreach (var c in neighborString) {
if (c == '1') {
tileValue += tileValues[i];
}
i++;
}
if (!autoTileTable.ContainsKey(tileValue)) {
autoTileTable.Add(tileValue, tileList);
}
// find each ? and add that to the tile value and add that as next entries
i = 0;
var listOfNeighbors = new List();
foreach (var c in neighborString) {
if (c == '?') {
listOfNeighbors.Add(tileValues[i]);
}
i++;
}
// Find every combination of the list of neighbors
var powerset = Util.GetPowerSet(listOfNeighbors);
foreach (var set in powerset) {
var t = tileValue;
foreach (var n in set) {
t += n;
}
if (!autoTileTable.ContainsKey(t)) {
autoTileTable.Add(t, tileList);
}
}
tileNumber++;
}
}
///
/// Load tiles in from a GridCollider and choose tiles based on the shape of the grid.
///
/// The GridCollider to reference.
/// The layer to place the tiles on.
public void LoadGridAutoTile(GridCollider grid, string layer = "") {
if (autoTileTable == null) {
SetAutoTileData(autoTileDefaultData);
}
for (var i = 0; i < grid.TileColumns; i++) {
for (var j = 0; j < grid.TileRows; j++) {
if (grid.GetTile(i, j)) {
int tileValue = 0;
/*
* auto tiling grid
*
* 128 001 016
* 008 ___ 002
* 064 004 032
*
*/
if (grid.GetTile(i - 1, j - 1)) {
tileValue += 128;
}
if (grid.GetTile(i, j - 1)) {
tileValue += 1;
}
if (grid.GetTile(i + 1, j - 1)) {
tileValue += 16;
}
if (grid.GetTile(i + 1, j)) {
tileValue += 2;
}
if (grid.GetTile(i + 1, j + 1)) {
tileValue += 32;
}
if (grid.GetTile(i, j + 1)) {
tileValue += 4;
}
if (grid.GetTile(i - 1, j + 1)) {
tileValue += 64;
}
if (grid.GetTile(i - 1, j)) {
tileValue += 8;
}
if (autoTileTable.ContainsKey(tileValue)) {
tileValue = Rand.ChooseElement(autoTileTable[tileValue]);
}
SetTile(i, j, tileValue, layer);
}
}
}
}
///
/// Load tiles in from a GridCollider.
///
/// The GridCollider to reference.
/// The color to set tiles that are collidable on the grid.
/// The layer to place the tiles on.
public void LoadGrid(GridCollider grid, Color color, Enum layer) {
LoadGrid(grid, color, Util.EnumValueToString(layer));
}
///
/// Get the layer name for a specific layer on the tilemap.
///
/// The layer depth id.
/// The string name of the layer.
public string LayerName(int layer) {
foreach (var l in layerNames) {
if (l.Value == layer) {
return l.Key;
}
}
return null;
}
///
/// Get the layer depth of a layer on the tilemap by name.
///
/// The string layer name.
/// The layer depth id.
public int LayerDepth(string layer) {
return layerNames[layer];
}
///
/// Get the layer depth of a layer on the tilemap by enum value.
///
/// The enum value layer.
/// The layer depth id.
public int LayerDepth(Enum layer) {
return LayerDepth(Util.EnumValueToString(layer));
}
///
/// Load the tilemap with a color based on a string.
///
/// The string data to load.
/// The color to fill occupied tiles with.
/// The character that represents an empty tile.
/// The character that represents a filled tile.
/// The layer to place the tiles on.
public void LoadString(string source, Color color = null, char empty = '0', char filled = '1', string layer = "") {
int xx = 0, yy = 0;
if (color == null) {
color = Color.Red;
}
for (int i = 0; i < source.Length; i++) {
if (source[i] != empty && source[i] != filled) continue;
if (xx == TileColumns) {
xx = 0;
yy++;
}
if (source[i] == filled) {
SetTile(xx, yy, color, layer);
}
xx++;
}
}
///
/// Load the tilemap with a color based on a string.
///
/// The string data to load.
/// The color to fill occupied tiles with.
/// The character that represents an empty tile.
/// The character that represents a filled tile.
/// The layer to place the tiles on.
public void LoadString(string source, Color color, char empty, char filled, Enum layer) {
LoadString(source, color, empty, filled, Util.EnumValueToString(layer));
}
///
/// Load the tilemap from a CSV formatted string.
///
/// The string data to load.
/// The character that separates columns in the CSV.
/// The character that separates rows in the CSV.
/// The layer to place the tiles on.
public void LoadCSV(string str, char columnSep = ',', char rowSep = '\n', string layer = "") {
bool u = UsePositions;
UsePositions = false;
string[] row = str.Split(rowSep);
int rows = row.Length;
string[] col;
int cols;
int x;
int y;
for (y = 0; y < rows; y++) {
if (row[y] == "") {
continue;
}
col = row[y].Split(columnSep);
cols = col.Length;
for (x = 0; x < cols; x++) {
if (col[x].Equals("") || Convert.ToInt32(col[x]) < 0) {
continue;
}
SetTile(x, y, Convert.ToInt16(col[x]), layer);
}
}
UsePositions = u;
}
///
/// Load the tilemap from a CSV formatted string.
///
/// The string data to load.
/// The character that separates columns in the CSV.
/// The character that separates rows in the CSV.
/// The layer to place the tiles on.
public void LoadCSV(string str, char columnSep, char rowSep, Enum layer) {
LoadCSV(str, columnSep, rowSep, Util.EnumValueToString(layer));
}
///
/// Remove a tile from the tilemap.
///
/// The tile's X position on the map.
/// The tile's Y position on the map.
/// The tile's layer.
/// The TileInfo for the cleared tile.
public TileInfo ClearTile(int tileX, int tileY, string layer = "") {
if (layer == "") layer = DefaultLayerName;
var t = GetTile(tileX, tileY, layer);
if (!UsePositions) {
tileX *= TileWidth;
tileY *= TileHeight;
}
tileX = (int)Util.Clamp(tileX, 0, Width - TileWidth);
tileY = (int)Util.Clamp(tileY, 0, Height - TileHeight);
RemoveTile(tileX, tileY, layerNames[layer]);
if (t != null) {
TileLayers[layerNames[layer]].Remove(t);
}
NeedsUpdate = true;
return t;
}
///
/// Remove a tile from the tilemap.
///
/// The tile's X position on the map.
/// The tile's Y position on the map.
/// The tile's layer.
/// The TileInfo for the cleared tile.
public TileInfo ClearTile(int tileX, int tileY, Enum layer) {
return ClearTile(tileX, tileY, Util.EnumValueToString(layer));
}
///
/// Clear all tiles on a specific layer.
///
/// The string layer name.
public void ClearLayer(string layer = "") {
if (layer == "") layer = DefaultLayerName;
TileLayers[layerNames[layer]].Clear();
NeedsUpdate = true;
}
///
/// Clear all tiles on a specific layer.
///
/// The enum value layer.
public void ClearLayer(Enum layer) {
ClearLayer(Util.EnumValueToString(layer));
}
///
/// Clear all tiles on all layers.
///
public void ClearAll() {
foreach (var kv in TileLayers) {
kv.Value.Clear();
}
NeedsUpdate = true;
}
///
/// Clear all tiles inside a specified rectangle.
///
/// The X position of the rectangle to clear.
/// The Y position of the rectangle to clear.
/// The width of tiles to clear.
/// The height of tiles to clear.
/// The layer to clear tiles from.
public void ClearRect(int tileX, int tileY, int tileWidth, int tileHeight, string layer = "") {
for (int xx = tileX; xx < tileX + tileWidth; xx++) {
for (int yy = tileY; yy < tileY + tileHeight; yy++) {
ClearTile(xx, yy, layer);
}
}
}
///
/// Add a new layer to the Tilemap.
///
/// The string name of the layer.
/// The depth of the tiles.
/// The depth id of the layer.
public int AddLayer(string name, int depth = 0) {
layerNames.Add(name, depth);
TileLayers.Add(depth, new List());
return TileLayers.Count - 1;
}
///
/// Add a new layer to the Tilemap.
///
/// The enum value of the layer.
/// The depth of the tiles.
/// The depth id of the layer.
public int AddLayer(Enum name, int depth = 0) {
return AddLayer(Util.EnumValueToString(name), depth);
}
///
/// Remove a layer from the Tilemap and delete that layer's tiles.
///
/// The name of the layer to delete.
public void RemoveLayer(string name) {
ClearLayer(name);
if (name != DefaultLayerName) {
TileLayers.Remove(layerNames[name]);
layerNames.Remove(name);
}
}
///
/// Remove a layer from the Tilemap and delete that layer's tiles.
///
/// The name of the layer to delete.
public void RemoveLayer(Enum name) {
RemoveLayer(Util.EnumValueToString(name));
}
///
/// Check if a layer exists.
///
/// The string name of the layer.
/// True if the layer exists.
public bool LayerExists(string name) {
return TileLayers.ContainsKey(layerNames[name]);
}
///
/// Check if a layer exists.
///
/// The enum value of the layer.
/// True if the layer exists.
public bool LayerExists(Enum name) {
return LayerExists(Util.EnumValueToString(name));
}
///
/// Merges another tilemap into this one.
///
/// The tilemap to merge into this one.
/// True if the other tilemap's base layer should be above this one's base layer.
public void MergeTilemap(Tilemap other, string layerPrefix = "", int layerOffset = -1) {
foreach (var layer in other.TileLayers) {
AddLayer(layerPrefix + other.LayerName(layer.Key), layer.Key + layerOffset);
TileLayers[layer.Key + layerOffset] = new List(other.TileLayers[layer.Key]);
}
}
///
/// Get the list of tiles on a specific layer.
///
/// The name of the layer.
/// A list of tiles on that layer.
public List GetTiles(string layerName) {
return TileLayers[LayerDepth(layerName)];
}
///
/// Get the list of tiles on a specific layer.
///
///
/// A list of tiles on that layer.
public List GetTiles(int layerDepth) {
return TileLayers[layerDepth];
}
///
/// Get the list of tiles on a specific layer.
///
/// The enum value of the layer.
/// A list of tiles on that layer.
public List GetTiles(Enum layerName) {
return TileLayers[LayerDepth(layerName)];
}
///
/// Get the index of a specific tile on the source Texture.
///
/// The tile to get the index of.
/// The index of the tile.
public int GetTileIndex(TileInfo tile) {
return tile.GetIndex(this);
}
#endregion
}
///
/// A class containing all the info to describe a specific tile.
///
public class TileInfo {
#region Public Fields
///
/// The X position of the tile.
///
public int X;
///
/// The Y position of the tile.
///
public int Y;
///
/// The X position of the source texture to render the tile from.
///
public int TX;
///
/// The Y position of the source texture to render the tile from.
///
public int TY;
///
/// The width of the tile.
///
public int Width;
///
/// The height of the tile.
///
public int Height;
///
/// Flipped tile options.
///
public bool FlipX;
public bool FlipY;
///
/// Flips the tile anti-diagonally, equivalent to a 90 degree rotation and a horizontal flip.
/// Combined with FlipX and FlipY you can rotate the tile any direction.
///
public bool FlipD;
///
/// The color of the tile, or the color to tint the texture.
///
public Color Color;
///
/// The alpha of the tile.
///
public float Alpha {
get { return Color.A; }
set { Color.A = value; }
}
#endregion
#region Constructors
public TileInfo(int x, int y, int tx, int ty, int width, int height, Color color = null, float alpha = 1) {
X = x;
Y = y;
TX = tx;
TY = ty;
Width = width;
Height = height;
if (color == null) {
Color = Color.White;
}
else {
Color = color;
}
Alpha = alpha;
}
#endregion
#region Public Methods
///
/// Returns the index of the tile on the source Texture of a Tilemap.
///
/// The Tilemap that uses the Texture to be tested against.
/// The index of the tile on the Tilemap's Texture.
public int GetIndex(Tilemap tilemap) {
return Util.OneDee(tilemap.Texture.Width / Width, TX / Width, TY / Height);
}
#endregion
#region Internal
internal Color tilemapColor = new Color();
internal Vector2f SFMLPosition {
get { return new Vector2f(X, Y); }
}
internal Vector2f SFMLTextureCoord {
get { return new Vector2f(TX, TY); }
}
internal Vertex CreateVertex(int x = 0, int y = 0, int tx = 0, int ty = 0) {
var tileColor = new Color(Color);
tileColor *= tilemapColor;
if (TX == -1 || TY == -1) {
return new Vertex(new Vector2f(X + x, Y + y), tileColor.SFMLColor);
}
return new Vertex(new Vector2f(X + x, Y + y), tileColor.SFMLColor, new Vector2f(TX + tx, TY + ty));
}
internal void AppendVertices(VertexArray array) {
if (!FlipD) {
if (!FlipX && !FlipY) {
array.Append(CreateVertex(0, 0, 0, 0)); //upper-left
array.Append(CreateVertex(Width, 0, Width, 0)); //upper-right
array.Append(CreateVertex(Width, Height, Width, Height)); //lower-right
array.Append(CreateVertex(0, Height, 0, Height)); //lower-left
}
if (FlipX && FlipY) {
array.Append(CreateVertex(0, 0, Width, Height));
array.Append(CreateVertex(Width, 0, 0, Height));
array.Append(CreateVertex(Width, Height, 0, 0));
array.Append(CreateVertex(0, Height, Width, 0));
}
if (FlipX & !FlipY) {
array.Append(CreateVertex(0, 0, Width, 0));
array.Append(CreateVertex(Width, 0, 0, 0));
array.Append(CreateVertex(Width, Height, 0, Height));
array.Append(CreateVertex(0, Height, Width, Height));
}
if (!FlipX & FlipY) {
array.Append(CreateVertex(0, 0, 0, Height));
array.Append(CreateVertex(Width, 0, Width, Height));
array.Append(CreateVertex(Width, Height, Width, 0));
array.Append(CreateVertex(0, Height, 0, 0));
}
}
else { //swaps lower-left corner with upper-right on all the cases
if (!FlipX && !FlipY) {
array.Append(CreateVertex(0, 0, 0, 0)); //upper-left
array.Append(CreateVertex(0, Height, Width, 0)); //upper-right
array.Append(CreateVertex(Width, Height, Width, Height)); //lower-right
array.Append(CreateVertex(Width, 0, 0, Height)); //lower-left
}
if (FlipX && FlipY) {
array.Append(CreateVertex(0, 0, Width, Height));
array.Append(CreateVertex(0, Height, 0, Height));
array.Append(CreateVertex(Width, Height, 0, 0));
array.Append(CreateVertex(Width, 0, Width, 0));
}
if (!FlipX & FlipY) {
array.Append(CreateVertex(0, 0, Width, 0));
array.Append(CreateVertex(0, Height, 0, 0));
array.Append(CreateVertex(Width, Height, 0, Height));
array.Append(CreateVertex(Width, 0, Width, Height));
}
if (FlipX & !FlipY) {
array.Append(CreateVertex(0, 0, 0, Height));
array.Append(CreateVertex(0, Height, Width, Height));
array.Append(CreateVertex(Width, Height, Width, 0));
array.Append(CreateVertex(Width, 0, 0, 0));
}
}
}
#endregion
}
}