Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Tilemap Importer - PyxelEdit to Unity

Tilemap Importer: PyxelEdit to Unity

This script adds a /Tools menu that lets you drag and drop Tilemap data as JSON and Tileset sprite map into Unity and create Tile instances.

This is designed to easily work with the new UnityEngine.Tilemaps link API and be easily configurable from Unity afterwards.

Installation

  • Add this to your assets into the /Editor directory.
  • Let your Unity IDE recompile

Usage

<iframe src="https://www.youtube.com/embed/nooMScdCLU4" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEngine.Tilemaps;
using System.IO;
public class CreateTilesFromTileset : EditorWindow
{
int padding = 5;
int buttonHeight = 25;
Texture2D texture2D;
GameObject baseTilemapObject;
Tile tile;
List<Tile> tiles;
public TextAsset jsonFile;
Grid grid;
public static string GetGameObjectPath(GameObject obj)
{
string path = "/" + obj.name;
while (obj.transform.parent != null)
{
obj = obj.transform.parent.gameObject;
path = "/" + obj.name + path;
}
return path;
}
[MenuItem("Tools/PyxelEdit/Import Tilemap Map Data")]
static void Init()
{
CreateTilesFromTileset window = ScriptableObject.CreateInstance<CreateTilesFromTileset>();
window.position = new Rect(Screen.width / 2, Screen.height / 2, 300, 300);
window.ShowPopup();
}
void OnGUI()
{
// Create generic base tile if none provided
if (tile == null)
{
tile = new Tile();
}
if (grid != null)
{
baseTilemapObject = grid.gameObject.transform.GetChild(0).gameObject;
}
EditorGUI.DropShadowLabel(new Rect(0, 0, position.width, 20),
"Create Tiles From Texture.");
texture2D = (Texture2D)EditorGUI.ObjectField(
new Rect(0 + padding, 30 + padding, position.width - padding * 2, 25),
"Tilemap as Texture2D: ",
texture2D,
typeof(Texture2D),
true
);
jsonFile = (TextAsset)EditorGUI.ObjectField(
new Rect(0 + padding, 60 + padding, position.width - padding * 2, 25),
"Tilemap JSON Data: ",
jsonFile,
typeof(TextAsset),
true
);
grid = (Grid)EditorGUI.ObjectField(
new Rect(0 + padding, 80 + padding, position.width - padding * 2, 25),
"Grid Target: ",
grid,
typeof(Grid),
true
);
bool isAccepted = GUI.Button(new Rect(0 + padding, (120 + padding), position.width - padding * 2, buttonHeight), "Go!");
bool isCanceled = GUI.Button(new Rect(0 + padding, (120 + buttonHeight + padding + padding), position.width - padding * 2, buttonHeight), "Cancel");
if (isAccepted)
{
Debug.Log("Building Tiles");
if (texture2D != null)
{
tiles = BuildTiles();
AddTilesToTilemap(grid);
Debug.Log("Loaded sprites as tiles!");
this.Close();
}
}
if (isCanceled)
{
Debug.Log("Canceled");
this.Close();
}
}
List<Tile> BuildTiles()
{
string path = AssetDatabase.GetAssetPath(texture2D);
Object[] assets = AssetDatabase.LoadAllAssetsAtPath(path);
List<Tile> tiles = new List<Tile>();
string fileExt = Path.GetExtension(path);
string fileNameWithoutExt = Path.GetFileNameWithoutExtension(path);
string fileNameWithExt = fileNameWithoutExt + fileExt;
string tilesDirPath = path.Replace(fileNameWithExt, fileNameWithoutExt + "_Tiles/");
// Make tiles dir if it doesnt exist
if (!Directory.Exists(tilesDirPath))
{
Directory.CreateDirectory(tilesDirPath);
}
List<Sprite> sprites = new List<Sprite>();
// Find sprites in assets dir
foreach (Object o in assets)
{
if (o.GetType() == typeof(Sprite))
{
sprites.Add((Sprite)o);
}
}
// Sort by name
sprites.Sort((x, y) =>
{
int xInt = int.Parse(x.name.Split('_')[1]);
int yInt = int.Parse(y.name.Split('_')[1]);
return xInt.CompareTo(yInt);
});
// Sprite nullSprite = sprites[0];
// Padding list to allow correct indices
// sprites.Insert(0, nullSprite);
foreach (Sprite s in sprites)
{
Tile t = Tile.CreateInstance<Tile>();
t.sprite = s;
string tilePath = tilesDirPath + s.name + ".asset";
AssetDatabase.CreateAsset(t, tilePath);
tiles.Add(t);
}
// Sort by name
tiles.Sort((x, y) =>
{
int xInt = int.Parse(x.name.Split('_')[1]);
int yInt = int.Parse(y.name.Split('_')[1]);
return xInt.CompareTo(yInt);
});
return tiles;
}
Tilemap CloneTilemap(Grid grid, string name)
{
Tilemap tilemap;
GameObject newTilemapContainer = Instantiate(baseTilemapObject, grid.gameObject.transform);
tilemap = newTilemapContainer.GetComponent<Tilemap>();
newTilemapContainer.name = name;
return tilemap;
}
public void AddTilesToTilemap(Grid grid)
{
if (grid == null)
{
Debug.Log("No grid reference is set!");
return;
}
string jsonString = jsonFile.ToString();
JTilemapData t = JsonUtility.FromJson<JTilemapData>(jsonString);
if (t.layers.Count > 0)
{
foreach (JTilemapData.Layer layer in t.layers)
{
GameObject obj = GameObject.Find(GetGameObjectPath(grid.gameObject) + "/" + layer.name);
Tilemap tilemap;
if (obj == null)
{
tilemap = CloneTilemap(grid, layer.name);
}
else
{
tilemap = obj.GetComponent<Tilemap>();
}
// Clears all tiles
tilemap.ClearAllTiles();
foreach (JTilemapData.Tile tile in layer.tiles)
{
if (tile.tile != -1)
{
// TODO: figure out why the first row is borked
int tileIdx = tile.tile - 1;
if (tile.tile <= 8)
{
tileIdx = tile.tile;
}
if (tileIdx >= tiles.Count || tileIdx < 0)
{
Debug.Log("Bad tile index: " + tileIdx);
Debug.Log("Tile name: " + tile.x + ", " + tile.y);
}
else
{
Vector3Int coords = NormalizeCoords(tile, t);
Tile tileObj = tiles[tileIdx];
tilemap.SetTile(
coords, tileObj
);
}
}
}
}
}
}
Vector3Int NormalizeCoords(JTilemapData.Tile tile, JTilemapData j)
{
int x = tile.x;
// int y = -tile.y;
int y = j.tileshigh - tile.y;
return new Vector3Int(x, y, 0);
}
void OnInspectorUpdate()
{
Repaint();
}
}
@Nfam0us

This comment has been minimized.

Copy link

commented Jul 11, 2019

So I put the CreateTilesFromTileset.cs file in the \Assets\JSON\Editor directory in my project, but the tool didn't come up in the menu. I closed and reopened the project.

Still no go.

Not sure what's going on.

Edit: Pretty sure it's because I'm using Unity 19.2. It doesn't even have a "tools" menu, apparently.
image

@omardelarosa

This comment has been minimized.

Copy link
Owner Author

commented Jul 13, 2019

Thanks for the heads up! I haven't updated my Unity version in a while, so I might need to tweak the script before it works on newer versions. I've been using version 2018.3.9f1

@Nfam0us

This comment has been minimized.

Copy link

commented Jul 13, 2019

@omardelarosa

This comment has been minimized.

Copy link
Owner Author

commented Jul 13, 2019

Have you tried updating this line 29 to a namespace inside a window:

[MenuItem("Tools/PyxelEdit/Import Tilemap Map Data")]

Looks like in the newer documentation it wants you to do something like:

[MenuItem("Window/CreateTilesFromTileset")]

In context it would be something like a static method like this ShowWindow method:

    // Add menu item named "My Window" to the Window menu
    [MenuItem("Window/CreateTilesFromTileset")]
    public static void ShowWindow()
    {
        //Show existing window instance. If one doesn't exist, make one.
        EditorWindow.GetWindow(typeof(CreateTilesFromTileset));
    }
@Nfam0us

This comment has been minimized.

Copy link

commented Jul 13, 2019

@Nfam0us

This comment has been minimized.

Copy link

commented Jul 13, 2019

@omardelarosa

This comment has been minimized.

Copy link
Owner Author

commented Jul 13, 2019

There's a decent one already in the AssetStore, but it costs a bit of $:

https://assetstore.unity.com/packages/tools/sprite-management/pyxel-edit-tilemap-importer-37329

I made mine because I wanted something a little simpler that didn't create prefabs for each tile. However, that one in the asset store is pretty good.

@Nfam0us

This comment has been minimized.

Copy link

commented Jul 13, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.