Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Tilemap LockPosition Only?

Discussion in '2D' started by castor76, May 10, 2021.

  1. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,511
    I would like to set flag of tile to something like "LockPosition" instead of "LockTransform".

    I still want the tiles to be able to rotate but lock the position, so I can use my custom logic for positioning the tiles.

    Is this possible? If not out of the box, how can I change GetTileData to get this right?
    Was wondering LockTransform is applied but doing my own rotation?
     
  2. ChuanXin

    ChuanXin

    Unity Technologies

    Joined:
    Apr 7, 2015
    Posts:
    1,068
    I am not sure I understand what you are looking for. Could you give some examples of the situations where you maintain your custom positioning?

    The LockTransform is mainly used to lock the transform to the one provided by GetTileData, especially for Tiles whose layout is driven based on its neighbours, eg. RuleTile or TerrainTile from the 2D Tilemap Extras.
     
  3. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,511
    I have situation where my tile position needs to be adjusted by its Y coordinates. I do this by deriving my own tile class from TileBase and then set the lock transform flag and then modify its transform matrix. This works but it also disables the ability to do rotation and flip of the tile using tile paint tool.
     
  4. ChuanXin

    ChuanXin

    Unity Technologies

    Joined:
    Apr 7, 2015
    Posts:
    1,068
    I do not think you need to set the LockTransform flag in this case to get the Y coordinates adjusted properly for this. Could I check how you are setting the Y coordinates? Possibly through GetTileData or through adjusting the position through the Select Tool?

    One issue I have noticed is that the position from GetTileData is overridden by the Tile Palette if you drop the Tile directly onto the Tile Palette and the Tile does not have LockTransform set. This will need to be fixed.
     
  5. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,511
    Code (CSharp):
    1.  
    2. public override void GetTileData(Vector3Int position, ITilemap tileMap, ref TileData tileData)
    3.         {
    4.             base.GetTileData(position, tileMap, ref tileData);
    5.  
    6.             tileData.sprite = sprite;
    7.             tileData.gameObject = gameObject;
    8.             tileData.flags = TileFlags.LockTransform;
    9.             tileData.colliderType = colliderType;
    10.             tileData.color = Color.white;
    11.                      
    12.              tileData.transform = transform * Matrix4x4.TRS(new Vector3(0, 0, position.y * 0.2f), Quaternion.identity, Vector3.one);          
    13.         }
    14.  
    This is code I am using to set the position. If I do not force set flag as LockTransform, upon painting the tile on the tilemap, the position do not get set as I have positioned them.
     
  6. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,319
    edit: on further testing, below is wrong, misremembered!

    I've had a similar problem.

    Situation: I wanted to set the position through SetTransformMatrix, but then I wanted the mirroring of the tile to be controlled within GetTileData.

    Problem: TileFlags can only support external or internal transform-setting, not both. By external, I mean tilemap.SetTransformMatrix, whereas by internal I mean from within GetTileData.

    TileFlags.LockTransform = GetTileData can set the transform
    TileFlags.None = need to set via Brush or SetTransformMatrix

    Unfortunate Workaround: Since it was more important to me to SetTransformMatrix the tile, this forced me into using TileFlags.None. As a result, I couldn't make the decision to mirror the texture via the matrix within GetTileData. So, I created manually-mirrored textures, which added a decent amount of texture cost.

    Ideally, I would have been able to adjust the Matrix partially within GetTileData (to set mirroring) and partially through SetTransformMatrix. There's no TileFlags option that supports doing both to the same tile, without setting the flags, then unsetting the flags, which would be a mess and perhaps not stable.

    Some of the finer details of this problem are a little fuzzy to me since I encountered it months ago and went with that workaround, but if I recall correctly the issue is further exacerbated by GetTileData(..., ref TileData tileData) not actually giving the current tileData! The Matrix info, iirc, was always Matrix.identity, even if it was changed from that. So, it wouldn't be possible to preserve the current (externally set) position information and mirror the x-scale from within GetTileData because the position would be lost via tileData.matrix being identity.

    Suggestion: TileFlags.SuperUnlocked - can set within GetTileData or externally and the current matrix/color/whatever is passed via ref TileData.
     
    Last edited: May 18, 2021
    castor76 likes this.
  7. ChuanXin

    ChuanXin

    Unity Technologies

    Joined:
    Apr 7, 2015
    Posts:
    1,068
    It looks like the issue for this would be default brush stores the transform matrix of the picked Tile and applies it onto the Tilemap when you are painting with that Tile. The procedure for picking and painting with the default GridBrush would be:
    • BrushPick:
      • GetTile: Brush stores Tile
      • GetTransformMatrix: Brush stores Transform Matrix of Tile (from Palette or the Tilemap)
    • BrushPaint
      • SetTile: Tile.GetTileData
      • SetTransformMatrix: Tilemap.SetTransformMatrix. This would override the transform matrix set in Tile.GetTileData if TileFlags.LockTransform is not set with the values stored from picking
    Potentially a different Brush or if a default Brush which has options in changing the way it handles the Transform Matrix when painting or picking Tiles would be suitable in this case then.

    Let us know what you think about this!
     
  8. ChuanXin

    ChuanXin

    Unity Technologies

    Joined:
    Apr 7, 2015
    Posts:
    1,068
    Could you share how you would like to handle the Transform Matrix through GetTileData and through SetTransformMatrix? It could be possible that you could be affected by the situation above through how the Default Brush behaves when picking and painting Tiles. Having more details would be great to help figure out a solution regarding the default Brush behaviour, or if it is something else altogether.

    Right now, ref TileData tileData does not include the previous Tile state on the Tilemap, but contains the default state of Tile in case each Tile property is not filled in by the user. You could still retrieve the previous Tile state in a roundabout way:

    Code (CSharp):
    1. public override void GetTileData(Vector3Int position, ITilemap tilemap, ref TileData tileData)
    2.     {
    3.         base.GetTileData(position, tilemap, ref tileData);
    4.         var baseMatrix = tilemap.GetComponent<Tilemap>().GetTransformMatrix(position);
    5.         tileData.transform = Matrix4x4.TRS(new Vector3(0f, yOffset, 0f), baseMatrix.rotation, Vector3.one);
    6.     }
     
  9. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,511
    Yes, I would actually expect something can be done about it so that custom position is preserved by the brush. Ideally, we should be able to override both position, rotation separately. Or anything that can help to archive this would be helpful.
     
  10. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,319
    After testing it some more, I suspect I was confused by a ~~brush thing~~ edit: script bug.. I think..

    Your proposed workaround for getting transform data should work, thanks.
     
    Last edited: May 18, 2021
  11. ChuanXin

    ChuanXin

    Unity Technologies

    Joined:
    Apr 7, 2015
    Posts:
    1,068
    We will try to prototype a Brush that can handle this situation and see if that can help!
     
    castor76 likes this.
  12. RonHClemons

    RonHClemons

    Joined:
    Mar 17, 2021
    Posts:
    5
    thanks for the information
     
  13. ChuanXin

    ChuanXin

    Unity Technologies

    Joined:
    Apr 7, 2015
    Posts:
    1,068
    @castor76 I posted the prototype brush at https://github.com/Unity-Technologi...nRotationBrush/HandlePositionRotationBrush.cs, which you can add to a project to try it out. This will override the Default Brush when added.

    There are a few options which you can toggle in the Brush inspector: Apply Position, Apply Rotation and Apply Color, which will apply each value accordingly when toggled. Transform Scale is not handled by the Brush right now unfortunately.

    Let us know if this works out for you and if there are any issues when using it. Thanks!
     
  14. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,511
    Hi, Thanks for the prototype, I have tried it but unfortunately, nothing is happening when I rotate my brush.
    I am painting with my own custom tile class, which could be the problem. I have already said above that I am using custom tile class so that I can custom force Z position.

    I have pm you the tilebase class I am working on. Thanks.
     
  15. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,511
    Hi @ChuanXin ,

    There is error with the HandlePositionRotationBrush

    IndexOutOfRangeException: Index was outside the bounds of the array.
    UnityEditor.Tilemaps.HandlePositionRotationBrush.BoxFill (UnityEngine.GridLayout gridLayout, UnityEngine.GameObject brushTarget, UnityEngine.BoundsInt position) (at Assets/Standard Assets/TileMap Auto Rule/2d-extras-master/Assets/Tilemap/Brushes/HandlePositionRotationBrush/Editor/HandlePositionRotationBrush.cs:52)
    UnityEditor.Tilemaps.PaintableSceneViewGrid.BoxFill (UnityEngine.BoundsInt position) (at Library/PackageCache/com.unity.2d.tilemap@1.0.0/Editor/PaintableSceneViewGrid.cs:185)
    UnityEditor.Tilemaps.PaintableGrid.HandleBoxTool () (at Library/PackageCache/com.unity.2d.tilemap@1.0.0/Editor/PaintableGrid.cs:505)
    UnityEditor.Tilemaps.PaintableGrid.OnGUI () (at Library/PackageCache/com.unity.2d.tilemap@1.0.0/Editor/PaintableGrid.cs:110)
    UnityEditor.Tilemaps.PaintableSceneViewGrid.OnSceneGUI (UnityEditor.SceneView sceneView) (at Library/PackageCache/com.unity.2d.tilemap@1.0.0/Editor/PaintableSceneViewGrid.cs:86)
    UnityEditor.SceneView.CallOnSceneGUI () (at <f9051bbfec05422cad88da502b7617ba>:0)
    UnityEditor.SceneView.HandleSelectionAndOnSceneGUI () (at <f9051bbfec05422cad88da502b7617ba>:0)
    UnityEditor.SceneView.OnGUI () (at <f9051bbfec05422cad88da502b7617ba>:0)
    UnityEditor.HostView.InvokeOnGUI (UnityEngine.Rect onGUIPosition, UnityEngine.Rect viewRect) (at <f9051bbfec05422cad88da502b7617ba>:0)
    UnityEditor.DockArea.DrawView (UnityEngine.Rect viewRect, UnityEngine.Rect dockAreaRect) (at <f9051bbfec05422cad88da502b7617ba>:0)
    UnityEditor.DockArea.OldOnGUI () (at <f9051bbfec05422cad88da502b7617ba>:0)
    UnityEngine.UIElements.IMGUIContainer.DoOnGUI (UnityEngine.Event evt, UnityEngine.Matrix4x4 parentTransform, UnityEngine.Rect clippingRect, System.Boolean isComputingLayout, UnityEngine.Rect layoutSize, System.Action onGUIHandler, System.Boolean canAffectFocus) (at <b39d465dd6ea4aab9c4f2f9e0a4117ba>:0)
    UnityEngine.UIElements.IMGUIContainer.HandleIMGUIEvent (UnityEngine.Event e, UnityEngine.Matrix4x4 worldTransform, UnityEngine.Rect clippingRect, System.Action onGUIHandler, System.Boolean canAffectFocus) (at <b39d465dd6ea4aab9c4f2f9e0a4117ba>:0)
    UnityEngine.UIElements.IMGUIContainer.HandleIMGUIEvent (UnityEngine.Event e, System.Action onGUIHandler, System.Boolean canAffectFocus) (at <b39d465dd6ea4aab9c4f2f9e0a4117ba>:0)
    UnityEngine.UIElements.IMGUIContainer.HandleIMGUIEvent (UnityEngine.Event e, System.Boolean canAffectFocus) (at <b39d465dd6ea4aab9c4f2f9e0a4117ba>:0)
    UnityEngine.UIElements.IMGUIContainer.SendEventToIMGUIRaw (UnityEngine.UIElements.EventBase evt, System.Boolean canAffectFocus, System.Boolean verifyBounds) (at <b39d465dd6ea4aab9c4f2f9e0a4117ba>:0)
    UnityEngine.UIElements.IMGUIContainer.SendEventToIMGUI (UnityEngine.UIElements.EventBase evt, System.Boolean canAffectFocus, System.Boolean verifyBounds) (at <b39d465dd6ea4aab9c4f2f9e0a4117ba>:0)
    UnityEngine.UIElements.IMGUIContainer.HandleEvent (UnityEngine.UIElements.EventBase evt) (at <b39d465dd6ea4aab9c4f2f9e0a4117ba>:0)
    UnityEngine.UIElements.CallbackEventHandler.HandleEventAtTargetPhase (UnityEngine.UIElements.EventBase evt) (at <b39d465dd6ea4aab9c4f2f9e0a4117ba>:0)
    UnityEngine.UIElements.MouseCaptureDispatchingStrategy.DispatchEvent (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel) (at <b39d465dd6ea4aab9c4f2f9e0a4117ba>:0)
    UnityEngine.UIElements.EventDispatcher.ApplyDispatchingStrategies (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel, System.Boolean imguiEventIsInitiallyUsed) (at <b39d465dd6ea4aab9c4f2f9e0a4117ba>:0)
    UnityEngine.UIElements.EventDispatcher.ProcessEvent (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel) (at <b39d465dd6ea4aab9c4f2f9e0a4117ba>:0)
    UnityEngine.UIElements.EventDispatcher.ProcessEventQueue () (at <b39d465dd6ea4aab9c4f2f9e0a4117ba>:0)
    UnityEngine.UIElements.EventDispatcher.OpenGate () (at <b39d465dd6ea4aab9c4f2f9e0a4117ba>:0)
    UnityEngine.UIElements.EventDispatcherGate.Dispose () (at <b39d465dd6ea4aab9c4f2f9e0a4117ba>:0)
    UnityEngine.UIElements.EventDispatcher.ProcessEvent (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel) (at <b39d465dd6ea4aab9c4f2f9e0a4117ba>:0)
    UnityEngine.UIElements.EventDispatcher.Dispatch (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel, UnityEngine.UIElements.DispatchMode dispatchMode) (at <b39d465dd6ea4aab9c4f2f9e0a4117ba>:0)
    UnityEngine.UIElements.BaseVisualElementPanel.SendEvent (UnityEngine.UIElements.EventBase e, UnityEngine.UIElements.DispatchMode dispatchMode) (at <b39d465dd6ea4aab9c4f2f9e0a4117ba>:0)
    UnityEngine.UIElements.UIElementsUtility.DoDispatch (UnityEngine.UIElements.BaseVisualElementPanel panel) (at <b39d465dd6ea4aab9c4f2f9e0a4117ba>:0)
    UnityEngine.UIElements.UIElementsUtility.UnityEngine.UIElements.IUIElementsUtility.ProcessEvent (System.Int32 instanceID, System.IntPtr nativeEventPtr, System.Boolean& eventHandled) (at <b39d465dd6ea4aab9c4f2f9e0a4117ba>:0)
    UnityEngine.UIElements.UIEventRegistration.ProcessEvent (System.Int32 instanceID, System.IntPtr nativeEventPtr) (at <b39d465dd6ea4aab9c4f2f9e0a4117ba>:0)
    UnityEngine.UIElements.UIEventRegistration+<>c.<.cctor>b__1_2 (System.Int32 i, System.IntPtr ptr) (at <b39d465dd6ea4aab9c4f2f9e0a4117ba>:0)
    UnityEngine.GUIUtility.ProcessEvent (System.Int32 instanceID, System.IntPtr nativeEventPtr, System.Boolean& result) (at <9ff04fda545c4aacb8dab659ad40b2f4>:0)


    If you use Paint Fill Box tool.
     
  16. ChuanXin

    ChuanXin

    Unity Technologies

    Joined:
    Apr 7, 2015
    Posts:
    1,068
    Will check it out, thanks!
     
  17. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,511
  18. ChuanXin

    ChuanXin

    Unity Technologies

    Joined:
    Apr 7, 2015
    Posts:
    1,068