Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

[RELEASED] Super Tilemap Editor

Discussion in 'Assets and Asset Store' started by CreativeSpore, Feb 21, 2016.

  1. DTAli

    DTAli

    Joined:
    Jan 22, 2016
    Posts:
    52
    Hi @CreativeSpore , we're looking to reduce loading times in our game. One of the major time sinks is the loading of tilemaps and their mesh creation/filling process. Our levels are procedurally generated with tons of rooms and rooms have lots of tilemaps. So we were thinking of precomputing all that mesh data and storing it as mesh asset so that process is not done at runtime. This would have to be done on a per chunk basis. If no mesh asset found, create one, then it can just modify that mesh at edit time, no filling or modification at runtime.

    - It would be nice if there was a built-in option to precompute meshes, I didn't see any, is there?

    - Can you think of any gotchas in the code I should be aware of while doing this?

    - Currently all our brushes are normal/non-animated. I assume animated brushes would go against this, wouldn't it? Unless some meshes can be dynamic and some can be static, thoughts?

    Cheers!
     
  2. antonioperez80

    antonioperez80

    Joined:
    Jun 8, 2017
    Posts:
    40
    Hey!!!
    My question is: how to get the grid position of a certain tile.

    Thank you!
     
    Last edited: Feb 2, 2021
  3. CreativeSpore

    CreativeSpore

    Joined:
    Nov 6, 2014
    Posts:
    1,190
    No, you need to create the event. Use the tilemap.Bounds to check if the mouse is inside the tilemap. Or check tilemap.GetTile at some position to check if there is any tile.
     
  4. CreativeSpore

    CreativeSpore

    Joined:
    Nov 6, 2014
    Posts:
    1,190
    Are you using Lightweight Render Pipeline? These shaders are not compatible with that.
    These shader are used if you want to make the tilemap compatible with Sprite Masks.
     
  5. CreativeSpore

    CreativeSpore

    Joined:
    Nov 6, 2014
    Posts:
    1,190
    antonioperez80 likes this.
  6. CreativeSpore

    CreativeSpore

    Joined:
    Nov 6, 2014
    Posts:
    1,190
    You can change the chunk size to 8 to enable dynamic batching
    upload_2021-2-7_15-59-45.png

    You could also make some modification in the code to generate the mesh only if the chunk is inside the camera view.
     
    antonioperez80 likes this.
  7. antonioperez80

    antonioperez80

    Joined:
    Jun 8, 2017
    Posts:
    40
    Hey!
    I add a normal map to my material for the tilemap but it has no effect.
    I use universal render pipeline materials. and 2d Light with the "Use normal map" check activated.

    What could be the problem?

    Thank you!;)
     
  8. Raseru

    Raseru

    Joined:
    Oct 4, 2013
    Posts:
    87
    Hi, I recently updated to the latest version from 1.6.2 and I noticed my carpet brushes when drawn in a thin line no longer work properly and have holes as it grabs the wrong pieces to create them. Is this intended?
     
    Last edited: Feb 9, 2021
  9. nuxvomo

    nuxvomo

    Joined:
    Jan 20, 2017
    Posts:
    12
    Hi there!
    I'm new to using Super Tilemap Editor.
    I basically need to create a level builder during run-time.
    During Play mode I've been able to edit in Scene View and see the changes in Game View but I am not able to edit in Game View.
    Also, it doesn't save my changes when I exit Play mode.

    Ultimately I want my players to be able to create their own levels and save them to use at a later time.
    Any guidance would be much appreciated!

    Thank you very much and love the quality of work on this asset so far.
     
  10. snugsound

    snugsound

    Joined:
    Mar 9, 2014
    Posts:
    17
    Question (or a possible bug?) re: colliders for auto-generated transition tiles when using a carpet brush:

    carpet-collider.png

    On the left you can see the actual colliders I defined. On the right, you can see the colliders for the auto-generated tiles (the right-most ones being the most obvious). Notice how they're all square. Is there any way to edit these colliders, or have them built properly from the ones I specified?
     
  11. snugsound

    snugsound

    Joined:
    Mar 9, 2014
    Posts:
    17
    Hi nuxvomo, as far as I know, the editing tools only work in the Unity Editor, so you will need to write your own level editor code. There's a section in the manual for "Updating a Tilemap by scripting" that should get you on the right track but keep in mind you'll also need to create your own UI (toolbar, scrolling, etc.) as well as saving/loading logic.
     
  12. CreativeSpore

    CreativeSpore

    Joined:
    Nov 6, 2014
    Posts:
    1,190
    I remember to change the behaviour to fix some issues. Maybe it changed the way it worked before. Can you show me how it was supposed to be before?
     
  13. CreativeSpore

    CreativeSpore

    Joined:
    Nov 6, 2014
    Posts:
    1,190
    You need to enable this to make it work with subtiles like the ones created by CarpetBrush. upload_2021-3-27_12-30-15.png
     
  14. snugsound

    snugsound

    Joined:
    Mar 9, 2014
    Posts:
    17
    Thanks, I'll give that a try!
     
  15. GameDevSA

    GameDevSA

    Joined:
    Dec 12, 2016
    Posts:
    252
    Dear @CreativeSpore,

    I am having strange rendering issues with super tilemap editor if I use a resizeable window. Is this expected behaviour? Example below:
    upload_2021-3-29_13-3-46.png
    upload_2021-3-29_13-3-59.png

    Both examples are from the latest version of Super Tilemap Editor, 1.7, and from Unity 2020.3.1f1.

    I was actually using an older version of Unity, 2019.1.13f1, and an older version of Super Tilemap Editor, 1.5 and I've just rolled back to that version because my game was more stable (and is close to complete).

    The actual pixel art appears to be rendering correctly, it is the lines in Super Tilemap Editor that appear to be showing up. It only happens in scenes I have used Super Tilemap Editor - the main menu displays completely correctly. So I do not believe it is a rendering issue with the project settings, but of course I could be wrong.

    Just to clarify, no issues when the game is in full screen. It only happens if I set the game to a resizable screen, which is a highly requested feature, and start stretching the screen.

    I have tried adding scripts to force the camera to keep it's aspect ratio even if the window is a funny size, and even tried a pixel 2D perfect camera package, but they didn't help.

    Have you seen anything like this? Do you know some possible causes?
    Thank you.

    Kind regards,
    Stuart
     

    Attached Files:

    Last edited: Mar 29, 2021
  16. Raseru

    Raseru

    Joined:
    Oct 4, 2013
    Posts:
    87
    The problem is that you get fractions of pixels if you make something resizable as you can't guarantee things to be pixel perfect anymore. There are some other ways to fix this I believe, but one failsafe way to fix it is to extrude the edges, effectively making your 16x16 sprites into 17x17 (but still having the sprite sheet splitting 16x16) in case an edge pixel gets shown. A lot of tools will allow you to extrude/pad, including super tilemap editor (check the setting at the top of unity, SuperTilemapEditor -> Window -> Atlas Editor Window). It'll modify the original image so make a backup or perhaps another tool before you import it to Unity.
     
    CreativeSpore likes this.
  17. Raseru

    Raseru

    Joined:
    Oct 4, 2013
    Posts:
    87
    Whoops, somehow never noticed your post.

    So basically, before, carpet brushes used to automagically work while being 1 tile wide despite a carpet brush being made with 3x3/2x2 tiles. Diagonal lines could match the width of one-width carpet horizontal/vertical lines by interchanging between 1-2 tiles diagonally (see right side of first image, {1}->{2,3}->{4}->etc).

    I gave it an ugly pink to make it a little more obvious, top is the newer version, bottom is the older version. All directions of diagonal lines of this width are effected.

    So basically when a tile like #4 connects to adjacent tiles, it grabs the top-right tile in the 3x3 and places it in the bottom-left of #4 in the image, when it used to grab the bottom-left portion of the 2x2. Similarly, the top-right of #4 used to be top-right of the 2x2, and so on for each corner.

    My guess would be that if your carpet brush has exactly the same amount of white space as it has non-white space (for the 3x3 edges and center of 2x2), then it would work out in its current form, however if it's off a little you will get transparent spaces (basically if 3x3 has less transparent space, then the 2x2 would need the inverse of that, old version worked, new version doesn't)

    I mean if it's a design choice it's fine I can redesign it, wouldn't be too hard.
     

    Attached Files:

    Last edited: Apr 9, 2021
  18. CreativeSpore

    CreativeSpore

    Joined:
    Nov 6, 2014
    Posts:
    1,190
    Yes, it was for design. I remember it was not working properly in some other use cases (I don't remember now what cases they were) but if you can adapt to it it would be great because you could benefit also for the other fixed cases as well. Sorry for the inconvenience.
     
  19. lorewap3

    lorewap3

    Joined:
    Jun 24, 2020
    Posts:
    58
    Hi @CreativeSpore ,

    I recently purchased STE after trying out the 2D extras and I'm glad I did. No sense re-inventing all the great features you have here! It's an excellent asset!

    I do have a issue, though, that I'm not sure how to solve. Everything works fine, but I'm trying to play around with the materials and shader to swap out palettes and this is where the issue arises. I'm using this basic PaletteSwap shader asset I got from the asset store:
    https://assetstore.unity.com/packages/vfx/shaders/color-palette-swapper-shader-153978

    But it doesn't seem to be working as it should. I tested it out with one of the provided tileset and it appears to only swap out 2 colors. (I hue shifted from brown to green on the entire palette)
    upload_2021-4-14_18-21-34.png

    Edit: Doing more diligence on my part, I have the TilemapChunks exposed. I can see that each uses the Sprites-Default material, which I switched out for the PaletteSwap.

    I wouldn't expect you to help me debug shader issues, but any advice or suggestions as to how to go about debugging this would be most appreciated.

    Do I possibly need to go through the RenderTexture route to accomplish this? Have a camera specifically for capturing the tilemaps on it and and apply it to a Quad that has the shader on it? I'd honestly like to avoid this if possible as that will only display the color change in the Game view and not Scene view.

    I'm not afraid to get my hands dirty, I'm just not familiar with the system enough to know where to start. If you have any suggestions I'd be super grateful!

    Thanks!
    Will
     
    Last edited: Apr 15, 2021
  20. lorewap3

    lorewap3

    Joined:
    Jun 24, 2020
    Posts:
    58
    Hi @CreativeSpore !

    I know your time is valuable and I don't want to ask for help without doing my part, so I went through the 33 pages of forums to make sure an issue like this hasn't already been asked ;)

    My main goal is the ability to do a color palette swap using a shader similar to what I'm using for my sprites. These are the options as I understand them:
    1) RenderTexture - Render tilemaps to rendertexture and then apply shader to that texture. I don't like this route as the scene view won't display the changes without additional layering I'd have to manage. Just not a fan. Would rather do in shader code.
    2) Prefab method - Use the prefab method you have to instance a prefab instead of a tile. The prefab would have the SpriteRenderer on it and would work with the shader I have. Really don't like this option as it tanks performance and would create loads of gameobjects for the sake of a simple palette swap.
    3) Custom shader - This is the only option I see at the moment. Don't know exactly why it's not working with the palette swap shader I have now, but I imagine it has to do with rendering meshes. I'm thinking I just need to create a 2-pass shader that combines Sprite-Default and the PaletteTableSwap functionality into one shader.

    The main points I want to ensure are built in:
    - Do not decrease performance. No additional gameobjects.
    - Want to be able to see the palette change while painting, meaning the OnSceneGUI functions (or whatever one display the preview of the tile under the brush while painting) should display a preview of the tile about to be place as if it was already run through the shader. I think this will happen automatically when I create the custom shader? Or will I need to do anything else to ensure the preview uses the same shader?

    Do you think I'm on the right track? I'm not exactly sure how many (if at all) parts of the STE code I'll need to touch to implement this. I noticed in a lot of places you do a search for the default shaders. I'm assuming this is to ensure that a shader is set in the event it (or the material) gets nullified for some reason, but if you can think of any code points I'll need to touch to implement this please let me know!

    Thank you so much!
    Will
     
  21. CreativeSpore

    CreativeSpore

    Joined:
    Nov 6, 2014
    Posts:
    1,190
    No sure why the shader is not working, but I think it should work if you use a custom material for the tilemap using that shader.
    What is weird is that don't your custom material when checking the tilemapchunks.
    Did you set your custom material here?
    upload_2021-4-23_18-19-34.png
     
  22. lorewap3

    lorewap3

    Joined:
    Jun 24, 2020
    Posts:
    58
    Yes, that's where I set the material. I also tried showing the tilemap chunks and setting the material there in case that would make a difference, and it didn't.

    Here's a before and after picture to illustrate:
    Using default Sprites-Default material:
    upload_2021-4-26_21-34-34.png

    Using custom material and palette swap shader:
    upload_2021-4-26_21-19-0.png

    What I did was reduce the tilemap to only 3 colors for testing purposes. I'm setting the material in the renderer tab as I should.

    All of this introduces more questions, though, as if you look at this screenshot below you can see that it's rendering more than 3 colors, even with the default Sprites-Default shader:
    upload_2021-4-26_21-29-20.png

    And here's the texture file it's based on so you can see for yourself there are only 3 colors:
    STEBasicStone_3Col_Extended.png

    That could definitely explain why the palette swapping isn't working right if the colors are being manipulated somehow. And I don't think it has anything to do with the camera since I still see the additional colors in the export if I click "Export to Png file" and open the export.

    Do you have any idea as to how this might be happening? I don't even know where to start debugging this.

    Thanks,
    Will
     

    Attached Files:

  23. lorewap3

    lorewap3

    Joined:
    Jun 24, 2020
    Posts:
    58
    Hey guys. After all that typing and debugging the issue was super simple. The import process didn't set the compression to none. It was left on normal resulting in the color artifacts. After I set it to none they went away and the shader could match up the colors and swap them as expected.

    Thanks guys, if only for listening ;) Great tool!
     
    CreativeSpore likes this.
  24. Raseru

    Raseru

    Joined:
    Oct 4, 2013
    Posts:
    87
    So I got around to editing the carpet brush and honestly the features the way the old brush used to work were way too good to pass up. I'm not sure what the new carpet brush fixes, but the old one would allow you to draw thin carpets which is really cool and lets you have way more control for more intricate stuff. I attached a picture that shows a carpet brush used to draw a wall while being pretty thin (on top of wall is a roadbrush affixed on top of it but it isn't necessary).

    So I just made an extra brush to have both. Not sure if I can share the code so I'll share the edits:
    For v1.7.0:
    Make a copy of CarpetBrush and CarpetBrushEditor, rename them to ThinCarpetBrush and ThinCarpetBrushEditor, change any CarpetBrush references to Thin in the editor. Then for ThinCarpetBrush.cs, comment out lines 125-140 and 147-162 and paste after that:
    aSubTileData = new uint[] { InteriorCornerTileIds[0], InteriorCornerTileIds[1], InteriorCornerTileIds[2], InteriorCornerTileIds[3] };
     

    Attached Files:

    Last edited: Apr 30, 2021
    CreativeSpore likes this.
  25. CreativeSpore

    CreativeSpore

    Joined:
    Nov 6, 2014
    Posts:
    1,190
    Thanks for sharing this. To be honest, I don't remember exactly what it was, but this is what I found. Looks like I just added more cases, or that was my intention at least, but maybe it broke how it worked before upload_2021-5-3_11-36-7.png
     
    Raseru likes this.
  26. gato0429

    gato0429

    Joined:
    Mar 5, 2015
    Posts:
    22
    hi creative spore,

    Super tile map editor, I have been reviewing the tool and it is very attractive, my query is the following, will it have any functionality to create isometric maps? , can tools be edited at runtime? and supports the latest version of unity 2021. regards
     
  27. andytlin74

    andytlin74

    Joined:
    Jan 26, 2018
    Posts:
    2
    Hi! Thank you again for such an amazing tool!

    I have a quick question regarding asset preview of STE TIlemap Group set as a prefab. Is there anyway for the preview image to render all the tilemap in the tilemap group?

    upload_2021-6-10_15-17-43.png

    Thank you!
     
  28. GameDevSA

    GameDevSA

    Joined:
    Dec 12, 2016
    Posts:
    252
    I hear what you are saying, but I think this is more than that. I think it is a bug. It also happens in the editor. The below screenshot is taken from inside the Unity Editor. It's really not nice to look at and makes workflow harder - I am sure it didn't used to look this bad.

    Having said that, builds now look fine that I restrict the game to only being displayed at multiples of HD, in other words, it's always displaying at the correct ratio, and I have a script to adjust it for funny resolutions.

    However, looking bad in editor is really jamming up my creativity right now. I have to build the game to see it without these funky lines everywhere. They show up even with the Unity Gizmo's grid turned off.

    @CreativeSpore if you have a chance to comment please...

    upload_2021-6-24_15-42-14.png

    **Above image is in the Unity editor using Super Tilemap Editor**
     
    Last edited: Jun 24, 2021
  29. GameDevSA

    GameDevSA

    Joined:
    Dec 12, 2016
    Posts:
    252
    @CreativeSpore For reference, I have been using the Unity tilemap editor for some of the tiles, and the unity tilemap is not giving me funny lines. The below image is with the Unity tilemap editor - again, the image is inside the Unity editor, not in build:

    upload_2021-6-24_15-50-36.png
     
  30. GameDevSA

    GameDevSA

    Joined:
    Dec 12, 2016
    Posts:
    252
    @CreativeSpore A more accurate look at what super tilemap looks like in editor without the lighting effects, just super tilemap editor.

    ** EDIT ** However I have noticed it only is doing it on "some" scenes, not all of them. Any idea's what might be causing it? As best I can tell, the scenes are identical.

    But randomly Unity does sometimes give me errors to do with lighting and baking - related?

    upload_2021-6-24_16-0-38.png
     
    Last edited: Jun 24, 2021
  31. CreativeSpore

    CreativeSpore

    Joined:
    Nov 6, 2014
    Posts:
    1,190
    It happens for many reasons. One could be if you are using Pixel Snap. Or it could be related to the view size like when it's using an odd resolution. Shouldn't be a problem if you use a standard resolution and even less if you use a pixel perfect camera (snap the camera position to the pixel size)
    But you can get completely rid of it by using an Atlas with some extruded pixels (check the Atlas Creator Window) or you use some inner padding in the tilemap settings.
     
  32. Gushmeister

    Gushmeister

    Joined:
    Apr 30, 2018
    Posts:
    50
    Hello there!
    I read through the posts you did here, but didn't really find a solution for what I was searching for.

    I'm having a really big map, which seems to be too big, the bigger the map, the bigger is the performance-impact. I'm working on mobile, and having a chunksize of 60 seems to be too much for mobile.

    I tried changing the k_chunksize variable, but it seems like this hasn't change anything. When I change the value in code to 20 or even 8 (dynamic batching) and then press the "show chunks"-button, the chunks stay in the same place and just become smaller, but the count doesn't change and drawing now seems to be buggy. My map is still divided by 16 parts (i see the lines), and after reducing the chunksize in code, the chunks-count still stays the same, it doesn't show more chunks. Also when starting the game and then showing the chunks in hierarchy, it still generates just 16 Objects.

    What am I doing wrong?
     
  33. dock

    dock

    Joined:
    Jan 2, 2008
    Posts:
    603
    Unity_rOE82ARxde.png

    I'm getting 370 (!) warnings in Unity 2021.1.11 that come from the Clipper library. I deleted clipper.cs which seems to have stopped them... but I'm worried that it's important!! Any suggestions? I can't find clipper referenced elsewhere in my own code or third party assets. Is Clipper now a standard part of Unity perhaps?

    edit:

    I did some poking around in the Packages section and was able to find Clipper.cs in multiple different official Unity packages

    "Library\PackageCache\com.unity.2d.spriteshape@6.0.0\Samples~\Extras\Scripts\Clipper.cs (44 hits)"
    "Library\PackageCache\com.unity.2d.animation@6.0.3\Editor\ClipperLib\clipper.cs (44 hits)"
     
    Last edited: Jul 7, 2021
    TransmentalMe likes this.
  34. GameDevSA

    GameDevSA

    Joined:
    Dec 12, 2016
    Posts:
    252
    Thanks for your response. I believe I am using pixel snap but it was happening before that. View size seems to make no difference. My graphics are designed for HD, about 1/4 HD. I do not have a pixel perfect camera (working on that) but I do not think that would affect the editor?
     
  35. Gushmeister

    Gushmeister

    Joined:
    Apr 30, 2018
    Posts:
    50
    Hi, see this video to get rid of the lines, you don't need a pixel perfect camera.

     
  36. TransmentalMe

    TransmentalMe

    Joined:
    Sep 18, 2018
    Posts:
    1
    Did removing the script cause any issues with using Super Tilemap Editor?

    I'm seeing these same warnings as well. I'm targeting consoles so I have to make sure this won't conflict with certification for publishing. I also don't like building a product on a tool with warnings or errors as that could mean a major headache much later.
     
  37. dock

    dock

    Joined:
    Jan 2, 2008
    Posts:
    603
    Removing Clipper worked fine for my uses of STE, which are entirely prefab placement. I can’t vouch for edge cases. I agree that the author should provide a clear answer.
     
  38. dock

    dock

    Joined:
    Jan 2, 2008
    Posts:
    603
    Does anyone know how to shrink the Tile Palette in the inspector? It's making it hard for using the TileBrush objects because I have to scroll past this every time.
     

    Attached Files:

  39. dock

    dock

    Joined:
    Jan 2, 2008
    Posts:
    603
    It looks like the Tile Palette inspector has a bug for me. I wonder whether this is specific to Unity 202X. I've emailed support about it, as it's very fiddly to use Tile Brushes.
     

    Attached Files:

    Last edited: Aug 2, 2021
  40. dock

    dock

    Joined:
    Jan 2, 2008
    Posts:
    603
    Sorry for so many multi posts, but I was able to make a hacky fix by rearranging the inspector in TilesetControl. Hopefully this can help someone else.

    Unity_QFvUQKikfj.png

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEditor;
    5. using System;
    6. using System.Linq;
    7. using UnityEditorInternal;
    8.  
    9. namespace CreativeSpore.SuperTilemapEditor
    10. {
    11.     [Serializable]
    12.     public class TilesetControl
    13.     {
    14.         public delegate void OnSelectedDelegate(int id);
    15.         public OnSelectedDelegate OnTileSelected = delegate { };
    16.         public OnSelectedDelegate OnBrushSelected = delegate { };
    17.  
    18.         private class Styles
    19.         {
    20.             static Styles s_instance;
    21.             public static Styles Instance{get{ if (s_instance == null) s_instance = new Styles(); return s_instance;} }
    22.             public GUIStyle scrollStyle = new GUIStyle("ScrollView");
    23.             public GUIStyle customBox = new GUIStyle("Box");
    24.         }
    25.  
    26.         public Tileset Tileset
    27.         {
    28.             get { return m_tileset; }
    29.             set
    30.             {
    31.                 if (m_tileset != value)
    32.                 {
    33.                     m_updateScrollPos = false;
    34.                     m_tileset = value;
    35.                 }
    36.             }
    37.         }
    38.  
    39.         private Tileset m_tileset;
    40.         private bool m_displayBrushReordList = false;
    41.         private Vector2 m_tileScrollSpeed = Vector2.zero;
    42.         private int m_visibleTileCount = 1;
    43.         private List<uint> m_visibleTileList = new List<uint>();
    44.         private Rect m_rTileScrollSize;
    45.         private Rect m_rTileScrollArea;
    46.         private Rect m_rBrushScrollArea;
    47.         private float m_lastTime;
    48.         private float m_timeDt;
    49.         private Vector2 m_lastTileScrollMousePos;
    50.         private Color m_prevBgColor;
    51.         private TilesetBrush m_selectBrushInInspector;
    52.  
    53.         #region SharedTilesetData
    54.         private class SharedTilesetData
    55.         {
    56.             public Tileset tileset;
    57.             public ReorderableList tileViewList;
    58.             public ReorderableList brushList;
    59.             public Vector2 tilesScrollPos;
    60.             public Vector2 brushesScrollPos;
    61.             public int tileViewRowLength = 1;
    62.             public KeyValuePair<int, Rect> startDragTileIdxRect;
    63.             public KeyValuePair<int, Rect> endDragTileIdxRect;
    64.             public KeyValuePair<int, Rect> pointedTileIdxRect;
    65.         }
    66.         private SharedTilesetData m_sharedData;
    67.  
    68.        private Dictionary<Tileset, SharedTilesetData> m_dicTilesetSharedData = new Dictionary<Tileset, SharedTilesetData>();
    69.         private SharedTilesetData GetSharedTilesetData(Tileset tileset)
    70.         {
    71.             SharedTilesetData sharedData = null;
    72.             if (tileset)
    73.             {
    74.                 if (!m_dicTilesetSharedData.TryGetValue(tileset, out sharedData))
    75.                 {
    76.                     sharedData = new SharedTilesetData();
    77.                     sharedData.tileset = tileset;
    78.                     m_dicTilesetSharedData[tileset] = sharedData;
    79.                 }
    80.             }
    81.             return sharedData;
    82.         }
    83.         #endregion
    84.  
    85.         private bool m_updateScrollPos = false;
    86.         private MouseDblClick m_dblClick = new MouseDblClick();
    87.         public bool Display()
    88.         {
    89.            //NOTE: for performance, the brush animations has been disabled. Set needsRepaint to true to enable brush animation in the inspector.
    90.             bool needsRepaint = false;
    91.            AssetPreview.SetPreviewTextureCacheSize(256); //FIX clickeing issues when displaying multiple prefab previews (when a tile has a prefab attached
    92.             Event e = Event.current;
    93.             m_dblClick.Update();
    94.  
    95.            //FIX: when a tileset is changed, the layout change and during some frames, the BeginScrollView could return wrong values
    96.             // This will make sure the scroll position is updated after mouse is over the control
    97.             if (e.isMouse || e.type == EventType.ScrollWheel)
    98.             {
    99.                 m_updateScrollPos = true;
    100.             }
    101.  
    102.             // This way a gui exception is avoided
    103.             if( e.type == EventType.Layout && m_selectBrushInInspector != null)
    104.             {
    105.                 Selection.activeObject = m_selectBrushInInspector;
    106.                 m_selectBrushInInspector = null;
    107.             }
    108.  
    109.             if (m_lastTime == 0f)
    110.             {
    111.                 m_lastTime = Time.realtimeSinceStartup;
    112.             }
    113.             m_timeDt = Time.realtimeSinceStartup - m_lastTime;
    114.             m_lastTime = Time.realtimeSinceStartup;
    115.  
    116.             if (Tileset == null)
    117.             {
    118.                 EditorGUILayout.HelpBox("There is no tileset selected", MessageType.Info);
    119.                 return false;
    120.             }
    121.             else if (Tileset.AtlasTexture == null)
    122.             {
    123.                 EditorGUILayout.HelpBox("There is no atlas texture set", MessageType.Info);
    124.                 return false;
    125.             }
    126.             else if (Tileset.Tiles.Count == 0)
    127.             {
    128.                 EditorGUILayout.HelpBox("There are no tiles to show in the current tileset", MessageType.Info);
    129.                 return false;
    130.             }          
    131.  
    132.             m_sharedData = GetSharedTilesetData(Tileset);
    133.  
    134.             float visualTilePadding = 1;
    135.             bool isLeftMouseReleased = e.type == EventType.MouseUp && e.button == 0;
    136.             bool isRightMouseReleased = e.type == EventType.MouseUp && e.button == 1;
    137.             bool isInsideTileScrollArea = e.isMouse && m_rTileScrollArea.Contains(e.mousePosition);
    138.             bool isInsideBrushScrollArea = e.isMouse && m_rBrushScrollArea.Contains(e.mousePosition);
    139.  
    140.             // Create TileView ReorderableList
    141.             if (m_sharedData.tileViewList == null || m_sharedData.tileViewList.list != Tileset.TileViews)
    142.             {            
    143.                 m_sharedData.tileViewList = TilesetEditor.CreateTileViewReorderableList(Tileset);
    144.                 m_sharedData.tileViewList.onSelectCallback += (ReorderableList list) =>
    145.                 {
    146.                     /* NOTE: this will select the tileview for the painting brush. Commented just in case.
    147.                     if(list.index >= 0)
    148.                     {
    149.                         TileSelection tileSelection = Tileset.TileViews[list.index].tileSelection.Clone();
    150.                         tileSelection.FlipVertical();
    151.                         Tileset.TileSelection = tileSelection;
    152.                     }
    153.                     else*/
    154.                         RemoveTileSelection();
    155.                 };
    156.                 m_sharedData.tileViewList.onRemoveCallback += (ReorderableList list) =>
    157.                 {
    158.                     RemoveTileSelection();
    159.                 };
    160.             }
    161.  
    162.             // Draw TileView ReorderableList
    163.             {
    164.                 GUI.color = Color.cyan;
    165.                 GUILayout.BeginVertical(Styles.Instance.customBox);
    166.                 m_sharedData.tileViewList.index = Mathf.Clamp(m_sharedData.tileViewList.index, -1, Tileset.TileViews.Count - 1);
    167.                 m_sharedData.tileViewList.DoLayoutList();
    168.                 Rect rList = GUILayoutUtility.GetLastRect();
    169.                 if (e.isMouse && !rList.Contains(e.mousePosition))
    170.                 {
    171.                     m_sharedData.tileViewList.ReleaseKeyboardFocus();
    172.                 }
    173.                 GUILayout.EndVertical();
    174.                 GUI.color = Color.white;
    175.             }
    176.            TileView tileView = m_sharedData.tileViewList != null && m_sharedData.tileViewList.index >= 0 ? Tileset.TileViews[m_sharedData.tileViewList.index] : null;
    177.  
    178.             if (tileView == null)
    179.             {
    180.                // NOTE: this is a fast fix to allow changing the TileRowLength. At some point, the Tile Palette was based on the Tileset.Width and this cannot be modified by design.
    181.                 // So I have changed this to set the Width with the TileRowLength value
    182.  
    183.                //Tileset.TileRowLength = Mathf.Clamp(EditorGUILayout.IntField("TileRowLength", Tileset.TileRowLength), 1, Tileset.Width);
    184.                 EditorGUI.BeginChangeCheck();
    185.                Tileset.TileRowLength = Mathf.Clamp(EditorGUILayout.IntField("TileRowLength", Tileset.TileRowLength), 1, Tileset.Tiles.Count);
    186.                 if(EditorGUI.EndChangeCheck())
    187.                 {
    188.                     Tileset.Width = Tileset.TileRowLength;
    189.                 }
    190.             }
    191.  
    192.          
    193.             List<string> viewNameList = new List<string>() { "(All)" };
    194.             viewNameList.AddRange(Tileset.TileViews.Select(x => x.name));
    195.             string[] tileViewNames = viewNameList.ToArray();
    196.             int[] tileViewValues = Enumerable.Range(-1, Tileset.TileViews.Count + 1).ToArray();
    197.             EditorGUI.BeginChangeCheck();
    198.            m_sharedData.tileViewList.index = EditorGUILayout.IntPopup("Tileset View", m_sharedData.tileViewList.index, tileViewNames, tileViewValues);
    199.             if (EditorGUI.EndChangeCheck())
    200.             {
    201.                 RemoveTileSelection();
    202.             }
    203.  
    204.             // Draw Background Color Selector
    205.             Tileset.BackgroundColor = EditorGUILayout.ColorField("Background Color", Tileset.BackgroundColor);
    206.             if (m_prevBgColor != Tileset.BackgroundColor || Styles.Instance.scrollStyle.normal.background == null)
    207.             {
    208.                 m_prevBgColor = Tileset.BackgroundColor;
    209.                if (Styles.Instance.scrollStyle.normal.background == null) Styles.Instance.scrollStyle.normal.background = new Texture2D(1, 1) { hideFlags = HideFlags.DontSave };
    210.                 Styles.Instance.scrollStyle.normal.background.SetPixel(0, 0, Tileset.BackgroundColor);
    211.                 Styles.Instance.scrollStyle.normal.background.Apply();
    212.             }
    213.             //---
    214.  
    215.             // Draw Zoom Selector
    216.             EditorGUILayout.BeginHorizontal();
    217.             GUILayout.Label(EditorGUIUtility.FindTexture("ViewToolZoom"), GUILayout.Width(35f));
    218.             float visualTileZoom = EditorGUILayout.Slider(Tileset.VisualTileSize.x / Tileset.TilePxSize.x, 0.25f, 4f);
    219.             Tileset.VisualTileSize = visualTileZoom * Tileset.TilePxSize;
    220.            if (GUILayout.Button("Reset", GUILayout.Width(50f))) Tileset.VisualTileSize = new Vector2(32f * Tileset.TilePxSize.x / Tileset.TilePxSize.y, 32f);
    221.             EditorGUILayout.EndHorizontal();
    222.             //---
    223.  
    224.  
    225.             EditorGUILayout.BeginHorizontal();
    226.             string sBrushIdLabel = Tileset.SelectedBrushId > 0 ? " (id:" + Tileset.SelectedBrushId + ")" : "";
    227.             EditorGUILayout.LabelField("Brush Palette" + sBrushIdLabel, EditorStyles.boldLabel);
    228.             m_displayBrushReordList = EditorUtils.DoToggleButton("Display List", m_displayBrushReordList);
    229.             EditorGUILayout.EndHorizontal();
    230.  
    231.             string[] brushTypeArray = Tileset.GetBrushTypeArray();
    232.             if (brushTypeArray != null && brushTypeArray.Length > 0)
    233.                 Tileset.BrushTypeMask = EditorGUILayout.MaskField("Brush Mask", Tileset.BrushTypeMask, brushTypeArray);
    234.  
    235.             int tileRowLength = (int)(m_rTileScrollSize.width / (Tileset.VisualTileSize.x + visualTilePadding));
    236.             if (tileRowLength <= 0) tileRowLength = 1;
    237.             float fBrushesScrollMaxHeight = Screen.height / 4;
    238.            //commented because m_rTileScrollSize.width.height was changed to Screen.height;  fBrushesScrollMaxHeight -= fBrushesScrollMaxHeight % 2; // sometimes because size of tile scroll affects size of brush scroll, the height is dancing between +-1, so this is always taking the pair value
    239.             float fBrushesScrollHeight = Mathf.Min(fBrushesScrollMaxHeight, 4 + (Tileset.VisualTileSize.y + visualTilePadding) * (1 + (Tileset.Brushes.Count / tileRowLength)));
    240.             EditorGUILayout.BeginVertical(GUILayout.MinHeight(fBrushesScrollHeight));
    241.             if (m_displayBrushReordList)
    242.             {
    243.                 DisplayBrushReorderableList();
    244.             }
    245.             else
    246.             {
    247.                 bool refreshBrushes = false;
    248.                Vector2 brushesScrollPos = EditorGUILayout.BeginScrollView(m_sharedData.brushesScrollPos, Styles.Instance.scrollStyle);
    249.                 if (m_updateScrollPos) m_sharedData.brushesScrollPos = brushesScrollPos;
    250.                 {
    251.                     Rect rScrollView = new Rect(0, 0, m_rTileScrollSize.width, 0);
    252.                    tileRowLength = Mathf.Clamp((int)rScrollView.width / (int)(Tileset.VisualTileSize.x + visualTilePadding), 1, tileRowLength);
    253.                     if (Tileset.Brushes != null)
    254.                     {
    255.                        GUILayout.Space((Tileset.VisualTileSize.y + visualTilePadding) * (1 + (Tileset.Brushes.Count - 1) / tileRowLength));
    256.                         for (int i = 0, idx = 0; i < Tileset.Brushes.Count; ++i, ++idx)
    257.                         {
    258.                             Tileset.BrushContainer brushCont = Tileset.Brushes[i];
    259.                             if (brushCont.BrushAsset == null || brushCont.BrushAsset.Tileset != Tileset)
    260.                             {
    261.                                 refreshBrushes = true;
    262.                                 continue;
    263.                             }
    264.                             if (!brushCont.BrushAsset.ShowInPalette || !Tileset.IsBrushVisibleByTypeMask(brushCont.BrushAsset))
    265.                             {
    266.                                 --idx;
    267.                                 continue;
    268.                             }
    269.  
    270.                             int tx = idx % tileRowLength;
    271.                             int ty = idx / tileRowLength;
    272.                            Rect rVisualTile = new Rect(2 + tx * (Tileset.VisualTileSize.x + visualTilePadding), 2 + ty * (Tileset.VisualTileSize.y + visualTilePadding), Tileset.VisualTileSize.x, Tileset.VisualTileSize.y);
    273.                             //Fix Missing Tileset reference
    274.                             if(brushCont.BrushAsset.Tileset == null)
    275.                             {
    276.                                Debug.LogWarning("Fixed missing tileset reference in brush " + brushCont.BrushAsset.name + " Id("+brushCont.Id+")");
    277.                                 brushCont.BrushAsset.Tileset = Tileset;
    278.                             }
    279.                             uint tileData = Tileset.k_TileData_Empty;
    280.                             if (brushCont.BrushAsset.IsAnimated())
    281.                             {
    282.                                 tileData = brushCont.BrushAsset.GetAnimTileData();
    283.                             }
    284.                             else
    285.                             {
    286.                                 tileData = brushCont.BrushAsset.PreviewTileData();
    287.                             }
    288.                             TilesetEditor.DoGUIDrawTileFromTileData(rVisualTile, tileData, Tileset, brushCont.BrushAsset.GetAnimUV());
    289.                             if ((isLeftMouseReleased || isRightMouseReleased || m_dblClick.IsDblClick) && isInsideBrushScrollArea && rVisualTile.Contains(Event.current.mousePosition))
    290.                             {
    291.                                 Tileset.SelectedBrushId = brushCont.Id;
    292.                                 OnBrushSelected(brushCont.Id);
    293.                                 RemoveTileSelection();
    294.                                 if (m_dblClick.IsDblClick)
    295.                                 {
    296.                                     EditorGUIUtility.PingObject(brushCont.BrushAsset);
    297.                                     m_selectBrushInInspector = brushCont.BrushAsset;
    298.                                 }
    299.                                 if (isRightMouseReleased)
    300.                                 {
    301.                                     TilePropertiesWindow.Show(Tileset);
    302.                                 }
    303.                             }
    304.                             else if (Tileset.SelectedBrushId == brushCont.Id)
    305.                             {
    306.                                Rect rSelection = new Rect(2 + tx * (Tileset.VisualTileSize.x + visualTilePadding), 2 + ty * (Tileset.VisualTileSize.y + visualTilePadding), (Tileset.VisualTileSize.x + visualTilePadding), (Tileset.VisualTileSize.y + visualTilePadding));
    307.                                HandlesEx.DrawRectWithOutline(rSelection, new Color(0f, 0f, 0f, 0.1f), new Color(1f, 1f, 0f, 1f));
    308.                             }
    309.                         }
    310.                     }
    311.  
    312.                     if (refreshBrushes)
    313.                     {
    314.                         Tileset.RemoveInvalidBrushes();
    315.                         Tileset.UpdateBrushTypeArray();
    316.                     }
    317.                 }
    318.                 EditorGUILayout.EndScrollView();
    319.                 if (e.type == EventType.Repaint)
    320.                 {
    321.                     m_rBrushScrollArea = GUILayoutUtility.GetLastRect();
    322.                 }
    323.             }
    324.             EditorGUILayout.EndVertical();
    325.          
    326.             if (GUILayout.Button("Import all brushes found in the project"))
    327.             {
    328.                 TilesetEditor.AddAllBrushesFoundInTheProject(Tileset);
    329.                 EditorUtility.SetDirty(Tileset);
    330.             }
    331.  
    332.  
    333.  
    334.  
    335.  
    336.  
    337.             string sTileIdLabel = Tileset.SelectedTileId != Tileset.k_TileId_Empty? " (id:" + Tileset.SelectedTileId + ")" : "";
    338.             EditorGUILayout.LabelField("Tile Palette" + sTileIdLabel, EditorStyles.boldLabel);
    339.  
    340.             m_sharedData.tileViewRowLength = tileView != null ? tileView.tileSelection.rowLength : Tileset.TileRowLength;
    341.             // keeps values safe
    342.             m_sharedData.tileViewRowLength = Mathf.Max(1, m_sharedData.tileViewRowLength);
    343.  
    344.             float tileAreaWidth = m_sharedData.tileViewRowLength * (Tileset.VisualTileSize.x + visualTilePadding) + 4f;
    345.            float tileAreaHeight = (Tileset.VisualTileSize.y + visualTilePadding) * (1 + (m_visibleTileCount - 1) / m_sharedData.tileViewRowLength) + 4f;
    346.          
    347.            //float minTileScrollHeight = (Tileset.VisualTileSize.y + visualTilePadding) * 6f;// NOTE: GUILayout.MinHeight is not working with BeginScrollView          
    348.              Vector2 tilesScrollPos = EditorGUILayout.BeginScrollView(m_sharedData.tilesScrollPos, Styles.Instance.scrollStyle/*, GUILayout.MinHeight(minTileScrollHeight)*/);
    349.             if(m_updateScrollPos) m_sharedData.tilesScrollPos = tilesScrollPos;
    350.             {
    351.                 // Scroll Moving Drag
    352.                 if (e.type == EventType.MouseDrag && (e.button == 1 || e.button == 2))
    353.                 {
    354.                     m_sharedData.tilesScrollPos -= e.delta;
    355.                 }
    356.                 else
    357.                 {
    358.                     DoAutoScroll();
    359.                 }
    360.  
    361.                 if (e.isMouse)
    362.                 {
    363.                     m_lastTileScrollMousePos = e.mousePosition;
    364.                 }
    365.                 if (Tileset.Tiles != null)
    366.                 {
    367.                     GUILayoutUtility.GetRect(tileAreaWidth, tileAreaHeight);
    368.                     int lastVisibleTileCount = m_visibleTileCount;
    369.                     m_visibleTileCount = 0;
    370.                     List<uint> visibleTileList = new List<uint>();
    371.                     int tileViewWidth = tileView != null ? tileView.tileSelection.rowLength : Tileset.Width;
    372.                    int tileViewHeight = tileView != null ? ((tileView.tileSelection.selectionData.Count - 1) / tileView.tileSelection.rowLength) + 1 : Tileset.Height;
    373.                    int totalCount = ((((tileViewWidth - 1) / m_sharedData.tileViewRowLength) + 1) * m_sharedData.tileViewRowLength) * tileViewHeight;
    374.                     int tileIdOffset = 0;
    375.                     for (int i = 0; i < totalCount; ++i)
    376.                     {
    377.                        int tileId = GetTileIdFromIdx(i, m_sharedData.tileViewRowLength, tileViewWidth, tileViewHeight) + tileIdOffset;
    378.                         uint tileData = (uint)tileId;
    379.                         if (tileView != null && tileId != Tileset.k_TileId_Empty)
    380.                         {
    381.                             int viewIdx = tileId - tileIdOffset;
    382.                             if (viewIdx >= tileView.tileSelection.selectionData.Count)
    383.                             {
    384.                                 tileData = Tileset.k_TileData_Empty;
    385.                             }
    386.                             else
    387.                             {
    388.                                 tileData = tileView.tileSelection.selectionData[viewIdx];
    389.                             }
    390.                             tileId = (int)(tileData & Tileset.k_TileDataMask_TileId);
    391.                         }
    392.                         Tile tile = Tileset.GetTile(tileId);
    393.                         while (tile != null && tile.uv == default(Rect)) // skip invalid tiles
    394.                         {
    395.                             tile = Tileset.GetTile(++tileId);
    396.                             tileData = (uint)tileId;
    397.                             tileIdOffset = tileId;
    398.                         }
    399.                         visibleTileList.Add(tileData);
    400.  
    401.                         int tx = m_visibleTileCount % m_sharedData.tileViewRowLength;
    402.                         int ty = m_visibleTileCount / m_sharedData.tileViewRowLength;
    403.                        Rect rVisualTile = new Rect(2 + tx * (Tileset.VisualTileSize.x + visualTilePadding), 2 + ty * (Tileset.VisualTileSize.y + visualTilePadding), Tileset.VisualTileSize.x, Tileset.VisualTileSize.y);
    404.  
    405.                         // Optimization, skipping not visible tiles
    406.                         Rect rLocalVisualTile = rVisualTile; rLocalVisualTile.position -= m_sharedData.tilesScrollPos;
    407.                         if (!rLocalVisualTile.Overlaps(m_rTileScrollSize))
    408.                         {
    409.                             ; // Do Nothing
    410.                         }
    411.                         else
    412.                         //---
    413.                         {
    414.                             // Draw Tile
    415.                             if (tile == null)
    416.                             {
    417.                                HandlesEx.DrawRectWithOutline(rVisualTile, new Color(0f, 0f, 0f, 0.2f), new Color(0f, 0f, 0f, 0.2f));
    418.                             }
    419.                             else
    420.                             {
    421.                                HandlesEx.DrawRectWithOutline(rVisualTile, new Color(0f, 0f, 0f, 0.1f), new Color(0f, 0f, 0f, 0.1f));
    422.                                 TilesetEditor.DoGUIDrawTileFromTileData(rVisualTile, tileData, Tileset);                              
    423.                             }
    424.  
    425.                            Rect rTileRect = new Rect(2 + tx * (Tileset.VisualTileSize.x + visualTilePadding), 2 + ty * (Tileset.VisualTileSize.y + visualTilePadding), (Tileset.VisualTileSize.x + visualTilePadding), (Tileset.VisualTileSize.y + visualTilePadding));
    426.                             if (rVisualTile.Contains(e.mousePosition))
    427.                             {
    428.                                 if (e.type == EventType.MouseDrag && e.button == 0)
    429.                                    m_sharedData.pointedTileIdxRect = new KeyValuePair<int, Rect>(m_visibleTileCount, rTileRect);
    430.                                 else if (e.type == EventType.MouseDown && e.button == 0)
    431.                                    m_sharedData.startDragTileIdxRect = m_sharedData.pointedTileIdxRect = m_sharedData.endDragTileIdxRect = new KeyValuePair<int, Rect>(m_visibleTileCount, rTileRect);
    432.                                 else if (e.type == EventType.MouseUp && e.button == 0)
    433.                                 {
    434.                                    m_sharedData.endDragTileIdxRect = new KeyValuePair<int, Rect>(m_visibleTileCount, rTileRect);
    435.                                     DoSetTileSelection();
    436.                                 }
    437.                             }
    438.  
    439.                            if ((isLeftMouseReleased || isRightMouseReleased) && isInsideTileScrollArea && rVisualTile.Contains(e.mousePosition)
    440.                                 && (m_sharedData.startDragTileIdxRect.Key == m_sharedData.endDragTileIdxRect.Key) // and there is not dragging selection
    441.                                  && m_rTileScrollSize.Contains(e.mousePosition - m_sharedData.tilesScrollPos))// and it's inside the scroll area
    442.                             {
    443.                                 Tileset.SelectedTileId = tileId;
    444.                                 OnTileSelected(tileId);
    445.  
    446.                                 //Give focus to SceneView to get key events
    447.                                 FocusSceneView();
    448.  
    449.                                 if(isRightMouseReleased)
    450.                                 {
    451.                                     TilePropertiesWindow.Show(Tileset);
    452.                                 }
    453.                             }
    454.                             else if (tile != null && Tileset.SelectedTileId == tileId)
    455.                             {
    456.                                HandlesEx.DrawRectWithOutline(rTileRect, new Color(0f, 0f, 0f, 0.1f), new Color(1f, 1f, 0f, 1f));
    457.                             }                          
    458.                         }
    459.  
    460.                         ++m_visibleTileCount;
    461.                     }
    462.                     m_visibleTileList = visibleTileList;
    463.                     if (lastVisibleTileCount != m_visibleTileCount)
    464.                         needsRepaint |= true;
    465.  
    466.                     // Draw selection rect
    467.                    if (m_sharedData.startDragTileIdxRect.Key != m_sharedData.pointedTileIdxRect.Key /*&& m_startDragTileIdxRect.Key == m_endDragTileIdxRect.Key*/)
    468.                     {
    469.                        Rect rSelection = new Rect(m_sharedData.startDragTileIdxRect.Value.center, m_sharedData.pointedTileIdxRect.Value.center - m_sharedData.startDragTileIdxRect.Value.center);
    470.                        rSelection.Set(Mathf.Min(rSelection.xMin, rSelection.xMax), Mathf.Min(rSelection.yMin, rSelection.yMax), Mathf.Abs(rSelection.width), Mathf.Abs(rSelection.height));
    471.                         rSelection.xMin -= m_sharedData.startDragTileIdxRect.Value.width / 2;
    472.                         rSelection.xMax += m_sharedData.startDragTileIdxRect.Value.width / 2;
    473.                         rSelection.yMin -= m_sharedData.startDragTileIdxRect.Value.height / 2;
    474.                         rSelection.yMax += m_sharedData.startDragTileIdxRect.Value.height / 2;
    475.                         HandlesEx.DrawRectWithOutline(rSelection, new Color(0f, 0f, 0f, 0.1f), new Color(1f, 1f, 1f, 1f));
    476.                     }
    477.                 }
    478.             }
    479.             EditorGUILayout.EndScrollView();
    480.             if (e.type == EventType.Repaint)
    481.             {
    482.                 m_rTileScrollArea = GUILayoutUtility.GetLastRect();
    483.                 Rect lastTileScrollSize = m_rTileScrollSize;
    484.                 m_rTileScrollSize = m_rTileScrollArea;
    485.                m_rTileScrollSize.position = Vector2.zero; // reset position to the Contains and Overlaps inside the tile scroll view without repositioning the position of local positions
    486.                 if (tileAreaWidth > m_rTileScrollSize.width)
    487.                     m_rTileScrollSize.height -= GUI.skin.verticalScrollbar.fixedWidth;
    488.                 if (tileAreaHeight > m_rTileScrollSize.height)
    489.                     m_rTileScrollSize.width -= GUI.skin.verticalScrollbar.fixedWidth;
    490.                 if (lastTileScrollSize != m_rTileScrollSize)
    491.                     needsRepaint |= true;
    492.             }
    493.  
    494.  
    495.  
    496.  
    497.  
    498.             needsRepaint |= Event.current.isMouse;
    499.             return needsRepaint;
    500.         }
    501.  
    502.         private void DisplayBrushReorderableList()
    503.         {
    504.             Event e = Event.current;
    505.             if (m_sharedData.brushList == null || m_sharedData.brushList.list != Tileset.Brushes)
    506.             {
    507.                 if (e.type != EventType.Layout)
    508.                 {
    509.                     m_sharedData.brushList = TilesetEditor.CreateBrushReorderableList(Tileset);
    510.                     m_sharedData.brushList.onSelectCallback += (ReorderableList list) =>
    511.                     {
    512.                         Tileset.BrushContainer brushCont = Tileset.Brushes[list.index];
    513.                         Tileset.SelectedBrushId = brushCont.Id;
    514.                         RemoveTileSelection();
    515.                         if (m_dblClick.IsDblClick)
    516.                         {
    517.                             EditorGUIUtility.PingObject(brushCont.BrushAsset);
    518.                             m_selectBrushInInspector = brushCont.BrushAsset;
    519.                         }
    520.                     };
    521.                 }
    522.             }
    523.             else
    524.             {
    525.                 GUILayout.BeginVertical(Styles.Instance.customBox);
    526.                 m_sharedData.brushList.index = Tileset.Brushes.FindIndex(x => x.Id == Tileset.SelectedBrushId);
    527.                 m_sharedData.brushList.index = Mathf.Clamp(m_sharedData.brushList.index, -1, Tileset.Brushes.Count - 1);
    528.                 m_sharedData.brushList.elementHeight = Tileset.VisualTileSize.y + 10f;
    529.                 m_sharedData.brushList.DoLayoutList();
    530.                 Rect rList = GUILayoutUtility.GetLastRect();
    531.                 if (e.isMouse && !rList.Contains(e.mousePosition))
    532.                 {
    533.                     m_sharedData.brushList.ReleaseKeyboardFocus();
    534.                 }
    535.                 GUILayout.EndVertical();
    536.             }
    537.         }
    538.  
    539.         private void FocusSceneView()
    540.         {
    541.             if (SceneView.lastActiveSceneView != null)
    542.                 SceneView.lastActiveSceneView.Focus();
    543.             else if (SceneView.sceneViews.Count > 0)
    544.                 ((SceneView)SceneView.sceneViews[0]).Focus();
    545.         }
    546.  
    547.         private void DoAutoScroll()
    548.         {
    549.             Event e = Event.current;
    550.             if (m_rTileScrollSize.Contains(e.mousePosition - m_sharedData.tilesScrollPos))
    551.             {
    552.                 if (e.type == EventType.MouseDrag && e.button == 0)
    553.                 {
    554.                     Vector2 mouseMoveDisp = e.mousePosition - m_lastTileScrollMousePos;
    555.                     float autoScrollDist = 40;
    556.                     float autoScrollSpeed = 500;
    557.                     Vector2 mousePosition = e.mousePosition - m_sharedData.tilesScrollPos;
    558.                    float leftFactorX = mouseMoveDisp.x < 0f ? 1f - Mathf.Pow(Mathf.Clamp01(mousePosition.x / autoScrollDist), 2) : 0f;
    559.                    float rightFactorX = mouseMoveDisp.x > 0f ? 1f - Mathf.Pow(Mathf.Clamp01((m_rTileScrollSize.width - mousePosition.x) / autoScrollDist), 2) : 0f;
    560.                     float topFactorY = mouseMoveDisp.y < 0f ? 1f - Mathf.Pow(Mathf.Clamp01(mousePosition.y / autoScrollDist), 2) : 0f;
    561.                    float bottomFactorY = mouseMoveDisp.y > 0f ? 1f - Mathf.Pow(Mathf.Clamp01((m_rTileScrollSize.height - mousePosition.y) / autoScrollDist), 2) : 0f;
    562.                     m_tileScrollSpeed = autoScrollSpeed * new Vector2((-leftFactorX + rightFactorX), (-topFactorY + bottomFactorY));
    563.                 }
    564.                 else if (e.type == EventType.MouseUp)
    565.                 {
    566.                     m_tileScrollSpeed = Vector2.zero;
    567.                 }
    568.             }
    569.             else if (e.isMouse)
    570.             {
    571.                 m_tileScrollSpeed = Vector2.zero;
    572.             }
    573.  
    574.             m_sharedData.tilesScrollPos += m_timeDt * m_tileScrollSpeed;
    575.         }
    576.  
    577.         private int GetTileIdFromIdx(int idx, int rowLength, int width, int height)
    578.         {
    579.             int cWxH = rowLength * height;
    580.             int n = idx % cWxH;
    581.             if (((idx / cWxH) * rowLength) + (idx % rowLength) >= width)
    582.             {
    583.                 return Tileset.k_TileId_Empty;
    584.             }
    585.             return (n / rowLength) * width + idx % rowLength + (idx / cWxH) * rowLength;
    586.         }
    587.  
    588.         private void RemoveTileSelection()
    589.         {
    590.             m_sharedData.pointedTileIdxRect = m_sharedData.startDragTileIdxRect = m_sharedData.endDragTileIdxRect;
    591.             Tileset.TileSelection = null;
    592.         }
    593.  
    594.         private void DoSetTileSelection()
    595.         {
    596.             if (m_sharedData.startDragTileIdxRect.Key != m_sharedData.endDragTileIdxRect.Key)
    597.             {
    598.                int tx_start = Mathf.Min(m_sharedData.startDragTileIdxRect.Key % m_sharedData.tileViewRowLength, m_sharedData.endDragTileIdxRect.Key % m_sharedData.tileViewRowLength);
    599.                 int ty_start = Mathf.Min(m_sharedData.startDragTileIdxRect.Key / m_sharedData.tileViewRowLength, m_sharedData.endDragTileIdxRect.Key / m_sharedData.tileViewRowLength);
    600.                 int tx_end = Mathf.Max(m_sharedData.startDragTileIdxRect.Key % m_sharedData.tileViewRowLength, m_sharedData.endDragTileIdxRect.Key % m_sharedData.tileViewRowLength);
    601.                 int ty_end = Mathf.Max(m_sharedData.startDragTileIdxRect.Key / m_sharedData.tileViewRowLength, m_sharedData.endDragTileIdxRect.Key / m_sharedData.tileViewRowLength);
    602.                 List<uint> selectionData = new List<uint>();
    603.                 int tileIdx = 0;
    604.                for (int ty = ty_end; ty >= ty_start; --ty) // NOTE: this goes from bottom to top to fit the tilemap coordinate system
    605.                 {
    606.                     for (int tx = tx_start; tx <= tx_end; ++tx, ++tileIdx)
    607.                     {
    608.                         int visibleTileIdx = ty * m_sharedData.tileViewRowLength + tx;
    609.                         uint tileData = m_visibleTileList[visibleTileIdx];
    610.                         selectionData.Add(tileData);
    611.                     }
    612.                 }
    613.                 Tileset.TileSelection = new TileSelection(selectionData, tx_end - tx_start + 1);
    614.                 FocusSceneView(); //Give focus to SceneView to get key events
    615.             }
    616.         }
    617.     }
    618. }
    619.  
     
    CreativeSpore and SugoiDev like this.
  41. Plesioth

    Plesioth

    Joined:
    Jun 10, 2015
    Posts:
    6
    I updated to 1.7 because I was experiencing a frequent bug where I'd no longer be able to paint. I backed up before this, but when I was looking through collision on all the levels, this one has a strange pentagon that blocks the way. Any idea what it's about? It didn't show up if I uncheck optimized on put it on edge collider mode. Having it on polygon mode is pretty important, but I don't know what's going on here. Any ideas before I roll back?
     

    Attached Files:

  42. Plesioth

    Plesioth

    Joined:
    Jun 10, 2015
    Posts:
    6
    Huh, right after this, I noticed the new generation method property. Clipper mode seems to work. Is there an explanation of the differences between the modes? Despite looking fine, Default doesn't seem to work properly on any level, but Clipper is working.

    EDIT: This bug is still here and driving me nuts. Basically, randomly painting will stop working after the tilesheet graphic is refreshed. Usually because I'm drawing it. I've tried many things and the only thing that seems to work is restarting unity. Drivin' me bonkers. It just acts like the normal rect tool. I'm in unity 2018.4.29f1 and this seems to trigger at random. Do you have any information on it? It pretty much utterly kills my work flow and doesn't error.
     
    Last edited: Aug 24, 2021
  43. jazzcake_home

    jazzcake_home

    Joined:
    Aug 22, 2013
    Posts:
    2
    Hello, it looks great. I'm in trouble now with Unity tilemap renderer, it is so slow even with small map.. do not find how to solve yet. What is the renderer of your product? is it 2d sprite system of Unity? I'd like to know the performance of your product.
     
  44. SugoiDev

    SugoiDev

    Joined:
    Mar 27, 2013
    Posts:
    395
    Super Tilemap Editor's performance is excellent.
    I've used it with all sizes of maps, never had any performance issues.
     
    CreativeSpore likes this.
  45. CreativeSpore

    CreativeSpore

    Joined:
    Nov 6, 2014
    Posts:
    1,190
    It's not using sprites. That is too slow. It's using Mesh renderers per chunks to render the tiles.
     
  46. hexdump

    hexdump

    Joined:
    Dec 29, 2008
    Posts:
    443
    Guys could you anyone tell me if this is better than the built-in tilemap? I really don't like the workflow and prefer something more like tiled.

    By the way does this import tiled properties for tiles?

    Thanks in advance!
     
  47. SugoiDev

    SugoiDev

    Joined:
    Mar 27, 2013
    Posts:
    395
    In my opinion, it's much better than Unity's.
    Plus, you have source access and can fix/change anything without having to wait months or years for Unity to fix it.


    I never use the Tiled importer, so I'm not sure.
     
    CreativeSpore likes this.
  48. hexdump

    hexdump

    Joined:
    Dec 29, 2008
    Posts:
    443
    Thanks for the quick answer.

    Does at least support tile properties? I mean, can we assign data in the editor to tiles?

    Cheers!
     
  49. SugoiDev

    SugoiDev

    Joined:
    Mar 27, 2013
    Posts:
    395
    Yes. You can add properties and query/change them at runtime.
    You can also ADD properties at runtime.

    The manual's link on the site is not working, so I'm attaching it here so you can take a look.
    (Tile properties is on page 15)
     

    Attached Files:

    CreativeSpore and hexdump like this.
  50. Klyntoc

    Klyntoc

    Joined:
    Apr 17, 2016
    Posts:
    5
    Hi @CreativeSpore, I noticed an issue when trying URP (universal render pipeline) where Parallax stops working and in one project I could no longer paint tiles. The issue starts as soon as the pipeline asset is assigned in the project settings.

    Thanks