Skip to content

Instantly share code, notes, and snippets.

@omardelarosa
Created February 20, 2019 04:11
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save omardelarosa/859a05f8881fe089f7e389b399f690bb to your computer and use it in GitHub Desktop.
Save omardelarosa/859a05f8881fe089f7e389b399f690bb to your computer and use it in GitHub Desktop.
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
Copy link

Nfam0us 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
Copy link
Author

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
Copy link

Nfam0us commented Jul 13, 2019 via email

@omardelarosa
Copy link
Author

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
Copy link

Nfam0us commented Jul 13, 2019 via email

@Nfam0us
Copy link

Nfam0us commented Jul 13, 2019 via email

@omardelarosa
Copy link
Author

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
Copy link

Nfam0us commented Jul 13, 2019 via email

@Javaec
Copy link

Javaec commented Dec 16, 2020

Where can i find JTilemapData class?

@MadYeAd
Copy link

MadYeAd commented Jan 10, 2021

I can't find that class either or am I missing something here?

@omardelarosa
Copy link
Author

This is no longer maintained and references an old version of Unity 2018.3.9f1. Rebuild the missing interface for JTilemapData class, sorry.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment