Created
March 20, 2016 19:26
-
-
Save zaneclaes/a187ac4af6298b0a48f9 to your computer and use it in GitHub Desktop.
Tiled Map Spawner
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using UnityEngine.Rendering; | |
using UnityEditor; | |
using IsoTools.Tiled; | |
using IsoTools.Internal; | |
using System; | |
using System.IO; | |
using System.Linq; | |
using System.Collections.Generic; | |
namespace IsoTools.Tiled { | |
class MapSpawner : MonoBehaviour { | |
public List<GameObject> tileTemplates = null; | |
public TiledMapAsset tiledMap = null; | |
public Vector2 spritePivotPoint = new Vector2(0.5f, 0); | |
// Map gid -> sprite and template: | |
private Dictionary<int, Sprite> spriteMap = new Dictionary<int, Sprite>(); | |
private Dictionary<int, GameObject> templateMap = new Dictionary<int, GameObject>(); | |
void Awake() { | |
var assetPath = AssetDatabase.GetAssetPath(tiledMap); | |
if (string.IsNullOrEmpty(assetPath)) { | |
throw new UnityException(string.Format("not found tiled map asset ({0}) path", tiledMap.name)); | |
} | |
// Pre-load all the sprite objects for later usage... | |
for (int i = 0, e = tiledMap.Data.Tilesets.Count; i < e; ++i) { | |
TiledMapTilesetData tileset = tiledMap.Data.Tilesets [i]; | |
var path = Path.Combine(Path.GetDirectoryName(assetPath), tileset.ImageSource); | |
// Force alignment of sprites... | |
TextureImporter textureImporter = AssetImporter.GetAtPath(path) as TextureImporter; | |
textureImporter.isReadable = true; | |
List<SpriteMetaData> newData = new List<SpriteMetaData>(); | |
for (int k = 0; k < textureImporter.spritesheet.Length; k++) { | |
SpriteMetaData d = textureImporter.spritesheet [k]; | |
d.alignment = (int)SpriteAlignment.Custom; | |
d.pivot = spritePivotPoint; | |
newData.Add(d); | |
} | |
textureImporter.spritesheet = newData.ToArray(); | |
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate); | |
var assets = AssetDatabase.LoadAllAssetsAtPath(path); | |
var fn = Path.GetFileNameWithoutExtension(tileset.ImageSource); | |
// Load the sprite into the spriteMap: | |
for (int j = 0; j < tileset.TileCount; j++) { | |
int gid = tileset.FirstGid + j; | |
var name = string.Format("{0}_{1}", fn, gid); | |
spriteMap [gid] = assets.Where(p => p is Sprite && p.name == name).Select(p => p as Sprite).FirstOrDefault(); | |
if (!spriteMap [gid]) { | |
throw new UnityException(string.Format("sprite ({0}) for tile ({1}) not found", name, gid)); | |
} | |
templateMap [gid] = tileTemplates [0]; | |
} | |
// Load the template into the templateMap: | |
foreach (TiledMapTileData tileData in tileset.Tiles) { | |
TiledMapProperties props = new TiledMapProperties(tileData.Properties); | |
String templateName = props.GetAsString("template"); | |
foreach (GameObject template in tileTemplates) { | |
if (template.name == templateName) { | |
templateMap [tileData.Gid] = template; | |
} | |
} | |
} | |
} | |
// Spawn each layer in the map... | |
foreach (TiledMapLayerData layer in tiledMap.Data.Layers) { | |
SpawnLayer(tiledMap.Data, layer); | |
} | |
// Remove the spawner from the hierarichy. | |
Destroy(this); | |
} | |
/** | |
* Create all the tiles in a given layer | |
*/ | |
private void SpawnLayer(TiledMapData mapData, TiledMapLayerData layer) { | |
TiledMapProperties props = new TiledMapProperties(layer.Properties); | |
// The following code assumes mapData.renderorder = right-down | |
float z = props.GetAsFloat("z"); | |
for (int i = 0; i < layer.Tiles.Count; i++) { | |
int gid = layer.Tiles [i]; | |
if (gid == 0) { | |
continue; | |
} | |
Vector3 pos = new Vector3(mapData.Height - i / mapData.Height - 1, mapData.Width - i % mapData.Width - 1, z); | |
GameObject template = templateMap [gid] as GameObject; | |
GameObject container = Instantiate(template); | |
container.name = template.name + "_" + pos.x + "x" + pos.y + "x" + pos.z; | |
SpriteRenderer spriteRenderer = container.GetComponent<SpriteRenderer>(); | |
spriteRenderer.sprite = spriteMap [gid]; | |
IsoObject isoObject = container.GetComponent<IsoObject>(); | |
isoObject.position = pos; | |
// Correct the position of any rigidBody children: | |
IsoObject[] children = isoObject.GetComponentsInChildren<IsoObject>(); | |
foreach (IsoObject child in children) { | |
child.position = pos; | |
} | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections.Generic; | |
namespace IsoTools.Tiled { | |
public enum TiledMapOrientation { | |
Isometric | |
} | |
[System.Serializable] | |
public class TiledMapTileData { | |
public int Gid = 0; | |
public List<string> Properties = new List<string>(); | |
} | |
[System.Serializable] | |
public class TiledMapLayerData { | |
public string Name = ""; | |
public int OffsetX = 0; | |
public int OffsetY = 0; | |
public bool Visible = true; | |
public List<int> Tiles = new List<int>(); | |
public List<string> Properties = new List<string>(); | |
} | |
[System.Serializable] | |
public class TiledMapTilesetData { | |
public int FirstGid = 0; | |
public string Name = ""; | |
public int Margin = 0; | |
public int Spacing = 0; | |
public int TileWidth = 0; | |
public int TileHeight = 0; | |
public int TileCount = 0; | |
public int TileOffsetX = 0; | |
public int TileOffsetY = 0; | |
public string ImageSource = ""; | |
public List<string> Properties = new List<string>(); | |
public List<TiledMapTileData> Tiles = new List<TiledMapTileData>(); | |
} | |
[System.Serializable] | |
public class TiledMapData { | |
public int Width = 0; | |
public int Height = 0; | |
public int TileWidth = 0; | |
public int TileHeight = 0; | |
public TiledMapOrientation Orientation = TiledMapOrientation.Isometric; | |
public List<string> Properties = new List<string>(); | |
public List<TiledMapLayerData> Layers = new List<TiledMapLayerData>(); | |
public List<TiledMapTilesetData> Tilesets = new List<TiledMapTilesetData>(); | |
} | |
public class TiledMapAsset : ScriptableObject { | |
[HideInInspector] | |
public TiledMapData Data = new TiledMapData(); | |
public string Name = string.Empty; | |
public float PixelsPerUnit = 100.0f; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using UnityEditor; | |
using IsoTools.Tiled; | |
using System; | |
using System.IO; | |
using System.Linq; | |
using System.Xml; | |
using System.Xml.Linq; | |
using System.Reflection; | |
using System.Collections.Generic; | |
namespace IsoTools.Tiled.Internal { | |
class TiledMapPostprocessor : AssetPostprocessor { | |
static void OnPostprocessAllAssets( | |
string[] imported_assets, string[] deleted_assets, | |
string[] moved_assets, string[] moved_from_asset_paths) { | |
var tmx_assets = imported_assets | |
.Where(p => Path.GetExtension(p).ToLower().Equals(".tmx")); | |
foreach (var tmx_asset in tmx_assets) { | |
TmxAssetProcess(tmx_asset); | |
} | |
} | |
static void TmxAssetProcess(string tmx_asset) { | |
var tile_map_data = LoadTiledMapFromTmxFile(tmx_asset); | |
if (tile_map_data != null) { | |
var new_asset_path = Path.ChangeExtension(tmx_asset, ".asset"); | |
var new_asset = AssetDatabase.LoadAssetAtPath<TiledMapAsset>(new_asset_path); | |
if (!new_asset) { | |
new_asset = ScriptableObject.CreateInstance<TiledMapAsset>(); | |
AssetDatabase.CreateAsset(new_asset, new_asset_path); | |
} | |
new_asset.Data = tile_map_data; | |
new_asset.Name = Path.GetFileNameWithoutExtension(new_asset_path); | |
EditorUtility.SetDirty(new_asset); | |
AssetDatabase.SaveAssets(); | |
} | |
} | |
static TiledMapData LoadTiledMapFromTmxFile(string tmx_path) { | |
try { | |
var tmx_root_elem = XDocument.Load(tmx_path).Document.Root; | |
var tiled_map_data = new TiledMapData(); | |
LoadTiledMapOptsFromTmxRootElem(tmx_root_elem, tiled_map_data); | |
LoadTiledMapLayersFromTmxRootElem(tmx_root_elem, tiled_map_data); | |
LoadTiledMapTilesetsFromTmxRootElem(tmx_root_elem, tiled_map_data); | |
LoadTiledMapTilesetsTextures(tmx_path, tiled_map_data); | |
return tiled_map_data; | |
} catch (Exception e) { | |
Debug.LogErrorFormat("Parsing TMX file error: {0}", e.Message); | |
return null; | |
} | |
} | |
static void LoadTiledMapOptsFromTmxRootElem(XElement root_elem, TiledMapData data) { | |
data.Width = SafeLoadIntFromElemAttr(root_elem, "width", data.Width); | |
data.Height = SafeLoadIntFromElemAttr(root_elem, "height", data.Height); | |
data.TileWidth = SafeLoadIntFromElemAttr(root_elem, "tilewidth", data.TileWidth); | |
data.TileHeight = SafeLoadIntFromElemAttr(root_elem, "tileheight", data.TileHeight); | |
var orientation_str = root_elem.Attribute("orientation").Value; | |
switch (orientation_str) { | |
case "isometric": | |
data.Orientation = TiledMapOrientation.Isometric; | |
break; | |
default: | |
throw new UnityException(string.Format( | |
"unsupported orientation ({0})", | |
orientation_str)); | |
} | |
SafeLoadPropertiesFromOwnerElem(root_elem, data.Properties); | |
} | |
// ----------------------------- | |
// Layers | |
// ----------------------------- | |
static void LoadTiledMapLayersFromTmxRootElem(XElement root_elem, TiledMapData data) { | |
foreach (var layer_elem in root_elem.Elements("layer")) { | |
var layer = new TiledMapLayerData(); | |
LoadTiledMapLayerFromTmxLayerElem(layer_elem, layer); | |
data.Layers.Add(layer); | |
} | |
} | |
static void LoadTiledMapLayerFromTmxLayerElem(XElement layer_elem, TiledMapLayerData layer) { | |
layer.Name = SafeLoadStrFromElemAttr(layer_elem, "name", layer.Name); | |
layer.OffsetX = SafeLoadIntFromElemAttr(layer_elem, "offsetx", layer.OffsetX); | |
layer.OffsetY = SafeLoadIntFromElemAttr(layer_elem, "offsety", layer.OffsetY); | |
layer.Visible = SafeLoadBoolFromElemAttr(layer_elem, "visible", layer.Visible); | |
LoadTiledMapLayerTilesFromTmxLayerElem(layer_elem, layer); | |
SafeLoadPropertiesFromOwnerElem(layer_elem, layer.Properties); | |
} | |
static void LoadTiledMapLayerTilesFromTmxLayerElem(XElement layer_elem, TiledMapLayerData layer) { | |
foreach (var elem in layer_elem.Element("data").Elements("tile")) { | |
layer.Tiles.Add(SafeLoadIntFromElemAttr(elem, "gid", 0)); | |
} | |
} | |
// ----------------------------- | |
// Tilesets | |
// ----------------------------- | |
static void LoadTiledMapTilesetsFromTmxRootElem(XElement root_elem, TiledMapData data) { | |
foreach (var tileset_elem in root_elem.Elements("tileset")) { | |
var tileset = new TiledMapTilesetData(); | |
LoadTiledMapTilesetFromTmxTilesetElem(tileset_elem, tileset); | |
data.Tilesets.Add(tileset); | |
} | |
} | |
static void LoadTiledMapTilesetFromTmxTilesetElem(XElement tileset_elem, TiledMapTilesetData tileset) { | |
tileset.FirstGid = SafeLoadIntFromElemAttr(tileset_elem, "firstgid", tileset.FirstGid); | |
tileset.Name = SafeLoadStrFromElemAttr(tileset_elem, "name", tileset.Name); | |
tileset.Margin = SafeLoadIntFromElemAttr(tileset_elem, "margin", tileset.Margin); | |
tileset.Spacing = SafeLoadIntFromElemAttr(tileset_elem, "spacing", tileset.Spacing); | |
tileset.TileWidth = SafeLoadIntFromElemAttr(tileset_elem, "tilewidth", tileset.TileWidth); | |
tileset.TileHeight = SafeLoadIntFromElemAttr(tileset_elem, "tileheight", tileset.TileHeight); | |
tileset.TileCount = SafeLoadIntFromElemAttr(tileset_elem, "tilecount", tileset.TileCount); | |
tileset.TileOffsetX = SafeLoadIntFromElemAttr(tileset_elem.Element("tileoffset"), "x", tileset.TileOffsetX); | |
tileset.TileOffsetY = SafeLoadIntFromElemAttr(tileset_elem.Element("tileoffset"), "y", tileset.TileOffsetY); | |
tileset.ImageSource = SafeLoadStrFromElemAttr(tileset_elem.Element("image"), "source", tileset.ImageSource); | |
foreach (var tile_elem in tileset_elem.Elements("tile")) { | |
var tile = new TiledMapTileData(); | |
tile.Gid = tileset.FirstGid + SafeLoadIntFromElemAttr(tile_elem, "id", tileset.FirstGid + tile.Gid); | |
SafeLoadPropertiesFromOwnerElem(tile_elem, tile.Properties); | |
tileset.Tiles.Add(tile); | |
} | |
SafeLoadPropertiesFromOwnerElem(tileset_elem, tileset.Properties); | |
} | |
// ----------------------------- | |
// Textures | |
// ----------------------------- | |
static void LoadTiledMapTilesetsTextures(string tmx_path, TiledMapData data) { | |
foreach (var tileset in data.Tilesets) { | |
if (!string.IsNullOrEmpty(tileset.ImageSource)) { | |
var base_path = Path.GetDirectoryName(tmx_path); | |
var image_path = Path.Combine(base_path, tileset.ImageSource); | |
var importer = AssetImporter.GetAtPath(image_path) as TextureImporter; | |
if (!importer) { | |
throw new UnityException(string.Format( | |
"tileset ({0}) image importer not found ({1})", | |
tileset.Name, image_path)); | |
} | |
var method_args = new object[2]{ 0, 0 }; | |
typeof(TextureImporter) | |
.GetMethod("GetWidthAndHeight", BindingFlags.NonPublic | BindingFlags.Instance) | |
.Invoke(importer, method_args); | |
var image_width = (int)method_args [0]; | |
var image_height = (int)method_args [1]; | |
var meta_data = new List<SpriteMetaData>(); | |
for (var i = image_height - tileset.TileHeight - tileset.Margin; i >= tileset.Margin; i -= tileset.TileHeight + tileset.Spacing) { | |
for (var j = tileset.Margin; j <= image_width - tileset.Margin - tileset.TileWidth; j += tileset.TileWidth + tileset.Spacing) { | |
var meta_elem = new SpriteMetaData(); | |
meta_elem.name = string.Format( | |
"{0}_{1}", | |
Path.GetFileNameWithoutExtension(image_path), | |
meta_data.Count + tileset.FirstGid); | |
meta_elem.rect = new Rect(j, i, tileset.TileWidth, tileset.TileHeight); | |
meta_data.Add(meta_elem); | |
} | |
} | |
importer.spritesheet = meta_data.ToArray(); | |
importer.textureType = TextureImporterType.Sprite; | |
importer.spriteImportMode = SpriteImportMode.Multiple; | |
TextureImporterSettings texSettings = new TextureImporterSettings(); | |
importer.ReadTextureSettings(texSettings); | |
texSettings.spriteAlignment = (int)SpriteAlignment.BottomCenter; | |
importer.SetTextureSettings(texSettings); | |
AssetDatabase.ImportAsset(image_path, ImportAssetOptions.ForceUpdate); | |
} | |
} | |
} | |
// ----------------------------- | |
// Common | |
// ----------------------------- | |
static string SafeLoadStrFromElemAttr(XElement elem, string attr_name, string def_value) { | |
if (elem != null && elem.Attribute(attr_name) != null) { | |
return elem.Attribute(attr_name).Value; | |
} | |
return def_value; | |
} | |
static int SafeLoadIntFromElemAttr(XElement elem, string attr_name, int def_value) { | |
int value; | |
if (elem != null && int.TryParse(SafeLoadStrFromElemAttr(elem, attr_name, ""), out value)) { | |
return value; | |
} | |
return def_value; | |
} | |
static bool SafeLoadBoolFromElemAttr(XElement elem, string attr_name, bool def_value) { | |
int value; | |
if (elem != null && int.TryParse(SafeLoadStrFromElemAttr(elem, attr_name, ""), out value)) { | |
return value != 0; | |
} | |
return def_value; | |
} | |
static void SafeLoadPropertiesFromOwnerElem(XElement owner_elem, List<string> props) { | |
var props_elem = owner_elem != null ? owner_elem.Element("properties") : null; | |
if (props_elem != null) { | |
foreach (var prop_elem in props_elem.Elements("property")) { | |
var prop_name = SafeLoadStrFromElemAttr(prop_elem, "name", null); | |
var prop_value = SafeLoadStrFromElemAttr(prop_elem, "value", null); | |
if (!string.IsNullOrEmpty(prop_name) && prop_value != null) { | |
props.Add(prop_name); | |
props.Add(prop_value); | |
} | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment