Skip to content

Instantly share code, notes, and snippets.

@anzfactory
Last active August 29, 2015 14:22
Show Gist options
  • Save anzfactory/0d4afb048b04f2bb85f8 to your computer and use it in GitHub Desktop.
Save anzfactory/0d4afb048b04f2bb85f8 to your computer and use it in GitHub Desktop.
[Unity]TiledMapEditorで作ったファイルを読み込んでタイルを敷き詰めるスクリプト群 ( http://anz-note.tumblr.com/post/120453126046/unity-tiledmap )
/*********************************
2015-05-31 TiledMapデータ
(.xmlの要素に従って配置)
*********************************/
using System.Collections.Generic;
using System.Xml.Serialization;
using UniLinq;
[XmlRoot("map")]
public class TiledMap
{
public class TileSet
{
[XmlAttribute("firstgid")]
public int FirstGID;
[XmlAttribute("name")]
public string Name;
[XmlAttribute("tilewidth")]
public int TileWidth;
[XmlAttribute("tileheight")]
public int TileHeight;
[XmlElement("image")]
public Image SourceImage;
[XmlElement("tile")]
public List<Tile> Tiles;
}
public class Properties
{
[XmlElement("property")]
public List<Property> All;
public Property Find(string name)
{
if (this.All == null) {
return null;
}
foreach (var p in this.All) {
if (p.Name.Equals(name)) {
return p;
}
}
return null;
}
public override string ToString()
{
if (this.All == null || this.All.Count == 0) {
return "no properties...";
}
return string.Join("\n", this.All.Select(p => {
return p.ToString();
}).ToArray());
}
}
public class Property
{
[XmlAttribute("name")]
public string Name;
[XmlAttribute("value")]
public string Value;
public override string ToString()
{
return string.Format("key:{0} value:{1}", this.Name, this.Value);
}
}
public class Layer
{
[XmlAttribute("name")]
public string Name;
[XmlAttribute("width")]
public int Width;
[XmlAttribute("height")]
public int Height;
[XmlElement("data")]
public Data TileData;
}
public class Image
{
[XmlAttribute("source")]
public string Source;
[XmlAttribute("width")]
public int Width;
[XmlAttribute("height")]
public int Height;
public string SourceName
{
get {
return this.Source.Substring(0, Source.LastIndexOf("."));
}
}
}
public class Data
{
[XmlAttribute("encoding")]
public string Encoding;
[XmlElement("tile")]
public List<Tile> Tiles;
}
public class Tile
{
[XmlAttribute("id")]
public int ID;
[XmlAttribute("gid")]
public int GID;
[XmlElement("properties")]
public Properties Properties;
}
public class ObjectGroup
{
[XmlElement("object")]
public List<Object> Objects;
}
public class Object
{
[XmlAttribute("id")]
public int ID;
[XmlAttribute("name")]
public string Name;
[XmlAttribute("type")]
public string Type;
[XmlAttribute("x")]
public int X;
[XmlAttribute("y")]
public int Y;
[XmlAttribute("width")]
public int Width;
[XmlAttribute("height")]
public int Height;
[XmlElement("properties")]
public Properties Properties;
}
[XmlAttribute("version")]
public string Version;
[XmlAttribute("orientation")]
public string Orientation;
[XmlAttribute("width")]
public int Width; // タイル数
[XmlAttribute("height")]
public int Height; // タイル数
[XmlAttribute("tilewidth")]
public int TileWidth; // 1タイルの横幅
[XmlAttribute("tileheight")]
public int TileHeight; // 1タイルの縦幅
[XmlElement("tileset")]
public List<TileSet> TileSets;
[XmlElement("layer")]
public List<Layer> Layers;
[XmlElement("objectgroup")]
public List<ObjectGroup> ObjectGroups;
public class TiledData
{
public int Number;
public int ID; // レイヤー内での unique
public int GID; // 全レイヤー内での unique
public int X;
public int Y;
public List<Property> Properties;
public override string ToString()
{
return string.Format("tile[{0}] ID:{1} GID:{2}, x-y:{3}-{4}", this.Number, this.ID, this.GID, this.X, this.Y);
}
}
private Dictionary<int, List<Property>> allProperty;
public List<TiledData> GetLayerData(string name)
{
Layer targetLayer = this.GetLayer(name);
if (targetLayer == null) {
return null;
}
return this.GetLayerData(targetLayer);
}
public List<TiledData> GetLayerData(Layer targetLayer)
{
List<Tile> tiles = targetLayer.TileData.Tiles;
List<TiledData> grid = new List<TiledData>(this.Width * this.Height);
TiledData data = null;
var allproperty = this.getProperties(); // マップに設定されているプロパティを全取得
for(int y = 0; y < targetLayer.Height; y++) {
for(int x = 0; x < targetLayer.Width; x++) {
int tileNo = this.GetTileNo(x, y);
data = new TiledData();
data.GID = tiles[tileNo].GID;
data.ID = this.convertToIDFromGID(data.GID);
data.X = x;
data.Y = y;
if (allproperty == null) {
data.Properties = null;
} else {
data.Properties = allproperty.ContainsKey(data.ID) ? allproperty[data.ID] : null;
}
grid.Add( data );
}
}
return grid;
}
public Layer GetLayer(string name)
{
foreach(var l in this.Layers){
if(l.Name == name){
return l;
}
}
return null;
}
private Dictionary<int, List<Property>> getProperties()
{
// すでに一度ロードしていたらそれを返す
if (this.allProperty != null) {
return this.allProperty;
}
// MARK 複数タイルセットを考慮するならもう一手間
TileSet currentTiseSet = this.TileSets[0];
// マップによってはプロパティ設定が無いかもなので
if (currentTiseSet.Tiles == null || currentTiseSet.Tiles.Count == 0) {
return null;
}
this.allProperty = new Dictionary<int, List<Property>>();
foreach (Tile t in currentTiseSet.Tiles) {
// ここの id から gid を作って設定しておく
this.allProperty[t.ID] = t.Properties.All;
}
return this.allProperty;
}
public int GetTileNo(int x, int y)
{
return x + (y * this.Width);
}
private int convertToGIDFromID(int id)
{
// MARK 複数のtilesetに対応するなら firstgid をちゃんと見て考慮する必要がある
return id + 1;
}
private int convertToIDFromGID(int gid)
{
// MARK 複数のtilesetに対応するなら firstgid をちゃんと見て考慮する必要がある
return gid - 1;
}
}
/*********************************
2015-05-30
*********************************/
using UnityEngine;
using System.Collections.Generic;
using UniLinq;
public class TiledMapCreator : MonoBehaviour
{
public TextAsset TMX;
public Material TiledDefaultMaterial = null;
public string DirPath;
private TiledMap tiledMap = null;
private TiledMap.TileSet currentTileSet = null;
private List<Sprite> sliceTileSet = null;
private void Start()
{
// 読み込んでパース
this.tiledMap = XMLParser.LoadFromXml<TiledMap>(this.TMX);
// 敷き詰め
this.CreateTiledMap();
}
private void CreateTiledMap()
{
this.currentTileSet = this.tiledMap.TileSets[0]; // 複数はとりあえず想定しない
// タイルセット画像をスライスしていく
this.SliceTilseSet();
if (this.sliceTileSet == null || this.sliceTileSet.Count == 0) {
return;
}
// 敷き詰める
foreach (var layer in this.tiledMap.Layers) {
this.Tiled(layer);
}
// オブジェクト配置
this.SetUpObjects();
// カメラさんにプレイヤーを中央にして移すように移動してもらう
Camera.main.SendMessage("SetupPlayer");
}
private void SliceTilseSet()
{
string path = this.currentTileSet.SourceImage.SourceName;
Sprite textureMap = Resources.Load<Sprite>(this.DirPath + path);
if (textureMap == null) {
Debug.LogError("can not find tileset image..." + path);
return;
}
this.sliceTileSet = new List<Sprite>(this.tiledMap.Width * this.tiledMap.Height);
// スライスしていく
int width = this.currentTileSet.SourceImage.Width / this.currentTileSet.TileWidth;
int height = this.currentTileSet.SourceImage.Height / this.currentTileSet.TileHeight;
Vector2 pivot = new Vector2(0.5f, 0.5f);
int counter = 0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// 範囲ぎめ
Rect rect = new Rect (
x * this.tiledMap.TileWidth,
textureMap.texture.height - (y + 1) * this.tiledMap.TileHeight,
this.tiledMap.TileWidth,
this.tiledMap.TileHeight
);
// スライス
Sprite tile = Sprite.Create(textureMap.texture, rect, pivot, this.tiledMap.TileWidth);
// 格納
this.sliceTileSet.Add(tile);
counter++;
}
}
}
private void Tiled(TiledMap.Layer layer)
{
GameObject goLayer = new GameObject(layer.Name);
int layerIndex = LayerMask.NameToLayer(layer.Name);
if (layerIndex >= 0) {
goLayer.layer = layerIndex;
}
goLayer.transform.parent = this.gameObject.transform;
List<TiledMap.TiledData> tiles = this.tiledMap.GetLayerData(layer);
foreach (var tiledData in tiles) {
if (tiledData.GID == 0) {
// ブランクタイル
continue;
}
// タイルスプライトを作って設置
GameObject tile = this.CreateTileSprite(tiledData, layer.Name);
tile.transform.position = new Vector3(tiledData.X, tiledData.Y * -1, 0);
tile.transform.parent = goLayer.transform;
tile.layer = goLayer.layer;
}
}
private GameObject CreateTileSprite(TiledMap.TiledData tiledData, string layerName)
{
GameObject tile = new GameObject("tile_" + tiledData.GID);
SpriteRenderer tileRender = tile.AddComponent(typeof(SpriteRenderer)) as SpriteRenderer;
tileRender.sprite = this.sliceTileSet[tiledData.ID];
tileRender.sortingLayerName = layerName;
tileRender.material = this.TiledDefaultMaterial;
// Collision設定
this.SetCollision(tiledData, tile);
return tile;
}
private void SetCollision(TiledMap.TiledData tiledData, GameObject tile)
{
if (tiledData.Properties == null || tiledData.Properties.Count == 0) {
return;
}
bool hasCollision = tiledData.Properties.Where(t => {
return t.Name.Equals("IsCollision") && t.Value.Equals("1");
}).Any();
if (hasCollision) {
var boxCollider2d = tile.AddComponent<BoxCollider2D>();
boxCollider2d.size = new Vector2(0.9f, 0.9f); // ちょい小さくする
}
}
private void SetUpObjects()
{
if (this.tiledMap.ObjectGroups == null || this.tiledMap.ObjectGroups.Count == 0) {
Debug.Log("not find objects...");
return;
}
foreach (var objGroup in this.tiledMap.ObjectGroups) {
foreach (var obj in objGroup.Objects) {
var p = obj.Properties.Find("Path");
string path = "";
if (p != null) {
path = p.Value;
}
// TypeをPrefabの名前として扱う
GameObject go = Instantiate(
Resources.Load(path + obj.Type),
new Vector3(obj.X / obj.Width, obj.Y / obj.Height * -1, 0f),
this.gameObject.transform.rotation
) as GameObject;
if (obj.Properties == null) {
continue;
}
// レイヤーが指定されていればセット
p = obj.Properties.Find("Layer");
if (p != null) {
go.layer = LayerMask.NameToLayer(p.Value);
}
// Sorting Layerが指定されていればセット
p = obj.Properties.Find("Sort");
if (p != null) {
go.GetComponent<SpriteRenderer>().sortingLayerName = p.Value;
}
}
}
}
}
/*********************************
2015-05-31 XMLパーサー
*********************************/
using UnityEngine;
using System.Xml.Serialization;
public class XMLParser
{
public static T LoadFromXml<T> (TextAsset xml)
where T : class
{
if (xml == null) {
Debug.LogError("Can not file xml file!! .... ");
return null;
}
var ser = new XmlSerializer (typeof(T));
var stringReader = new System.IO.StringReader(xml.text);
var obj = ser.Deserialize(stringReader);
var retClass = (T)obj;
return retClass;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment