3
\$\begingroup\$

I'm using unity, with 2D Tilemaps (I'm doing something like an RPG)

I want to have a Tile which should be rendered with a random sprite.

When I use a tile like a tree that is bigger than the tile size and RandomTile, the draw order seems to get confused. Even if the sort order on the Tilemap Renderer is set appropriately, some of the tiles are drawing on top of the other tiles with no consistent pattern.

After stepping through with the Frame Debugger, it looks like all tiles with the same sprite are drawn at the same Draw Dynamic event under TilemapRenderer.Render.

enter image description here

I'm using the following script:

using System;
using System.Collections;
using System.Collections.Generic;

#if UNITY_EDITOR
using UnityEditor;
#endif

using UnityEngine;

namespace UnityEngine.Tilemaps
{
    [Serializable]
    public class RandomTile : Tile
    {
        [SerializeField]
        public Sprite[] m_Sprites;

        public override void GetTileData(Vector3Int location, ITilemap tileMap, ref TileData tileData)
        {
            base.GetTileData(location, tileMap, ref tileData);
            if ((m_Sprites != null) && (m_Sprites.Length > 0))
            {
                long hash = location.x;
                hash = (hash + 0xabcd1234) + (hash << 15);
                hash = (hash + 0x0987efab) ^ (hash >> 11);
                hash ^= location.y;
                hash = (hash + 0x46ac12fd) + (hash << 7);
                hash = (hash + 0xbe9730af) ^ (hash << 11);
                Random.InitState((int)hash);
                tileData.sprite = m_Sprites[(int) (m_Sprites.Length * Random.value)];
            }
        }

#if UNITY_EDITOR
        [MenuItem("Assets/Create/Random Tile")]
        public static void CreateRandomTile()
        {
            string path = EditorUtility.SaveFilePanelInProject("Save Random Tile", "New Random Tile", "asset", "Save Random Tile", "Assets");

            if (path == "")
                return;

            AssetDatabase.CreateAsset(ScriptableObject.CreateInstance<RandomTile>(), path);
        }
#endif
    }

#if UNITY_EDITOR
    [CustomEditor(typeof(RandomTile))]
    public class RandomTileEditor : Editor
    {
        private RandomTile tile { get { return (target as RandomTile); } }

        public override void OnInspectorGUI()
        {
            EditorGUI.BeginChangeCheck();
            int count = EditorGUILayout.DelayedIntField("Number of Sprites", tile.m_Sprites != null ? tile.m_Sprites.Length : 0);
            if (count < 0)
                count = 0;
            if (tile.m_Sprites == null || tile.m_Sprites.Length != count)
            {
                Array.Resize<Sprite>(ref tile.m_Sprites, count);
            }

            if (count == 0)
                return;

            EditorGUILayout.LabelField("Place random sprites.");
            EditorGUILayout.Space();

            for (int i = 0; i < count; i++)
            {
                tile.m_Sprites[i] = (Sprite) EditorGUILayout.ObjectField("Sprite " + (i+1), tile.m_Sprites[i], typeof(Sprite), false, null);
            }       
            if (EditorGUI.EndChangeCheck())
                EditorUtility.SetDirty(tile);
        }
    }
#endif
}

Is there any way to fix it?

\$\endgroup\$
  • \$\begingroup\$ I have the exact same issue. I'm using custom TileBase that changes sprite in TileData, and it breaks sort order. I have this bug in both 2017 and 2018 Unity. Have you found a solution? \$\endgroup\$ – Maksym H Jun 4 '18 at 16:50
0
\$\begingroup\$

I found a solution to this problem. I don't know if you are using a sprite sheet for the trees or not. If not then create a sprite sheet with all your trees in that. Link these sprites from the sheet to your tiles.

Explanation : Since the frame debugger shows one sprite being rendered after the another. The solution should be to render them all at the same time which should be possible through a sprite sheet.

Let me know if this worked for you. It did for me.

\$\endgroup\$
0
\$\begingroup\$

Solution: create a SpriteAtlas and put your tree sprites into it. The tiles will technically become part of one spritesheet, so they will be drawn during the same Draw Dynamic event.

(If you want to see the result straight in play mode, go to Edit —> Projects Settings —> Editor and set Sprite Packer Mode to Always Enabled).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.