Hey guys, Just wondering how to rotate tiles already placed on the tilemap. I want to rotate when right clicking it. Code (CSharp): if (!cursorInvalid && Input.GetMouseButtonDown(1)) { TileBase tile = map.GetTile(tileMousePos); if (tile != null) { tile.rotation = (tile.rotation + 90) % 360; map.RefreshTile(tileMousePos); } } Right click, if we have a tile, set a rotation value on it, call refresh. That calls GetTileData again. Which ends up calling: Code (CSharp): public override void GetTileData(Vector3Int position, ITilemap tilemap, ref TileData tileData) { Quaternion rot = Quaternion.Euler(0.0f, 0.0f, rotation); tileData.transform = Matrix4x4.TRS(Vector3.zero, rot, Vector3.one); } That's it. Why don't I see anything rotated? Very confused... (that function does other stuff in a overridden function, this is the function a level higher). Thanks for your help!
So, I found out that when I set the rotation value 'before' I place the tile, everything works fine and it rotates. But it doesn't visually change if I try to rotate it 'after' it's been placed already. Think this is yet another Unity bug?
Is tile null? have you debugged and put a breakpoint on Matrix4x4.TRS? Does the inspector show any rotation changes when .TRS() is called? Step through the code and let us know what you find.
I right clicked. The tile wasn't null, it set the rotation value to 90. The rotation value in the transform (tileData.transform.rotation) was 0.0, 0.0, 0.0, 1.0 before I set the transform with Matrix4x4.TRS. After, it was 0.0, 0.0, 0.7, 0.7.
0.7 doesn't sound right unless you are tweening? What values are being passed into .Euler()? 90f is going in and .7 is coming out?
Rotation value is 90 when entering GetTileData. rot.eulerAngles returns 0.0, 0.0, 90.0, but it comes out as 0.7 when using tileData.transform.rotation. I can't use transform.Rotate because tiledata.trasform is Matrix4x4, not the Transform class. But I can use Matrix4x4.Rotate. Doing so produces the same 0.0, 0.0, 0.7, 0.7 result without any visible rotation occurring.
a quaternion with (0,0,.7,.7) is normal for 90f rotation. The code you provided is working perfectly for me. Make sure you are actually setting the GameObject's rotation to Matrix4x4.rotation.
Here's my test code that works with a 90f rotation: Code (CSharp): Quaternion testq = Quaternion.Euler(0, 0, 90f); var m = Matrix4x4.Rotate(testq); // at this point, m.rotation is (0,0,.7,.7) _settingsMenu.transform.rotation = m.rotation; // in the inspector, _settingsMenu's rotation is 0, 0, 90
Using tileData.transform does allow for rotation. If I run my code before I place the tile then when I do place it it is rotated properly. But changing it on an already set tile doesn't work (even when tilemap.RefreshTile() is called). I'm considering it another bug...
Yeah, I can get around it that way. I suppose it works for now. But the bugs in this tilemap system...
The docs have an example of Scriptable Tiles that change and rotate a tile based on neighboring tiles. https://docs.unity3d.com/Manual/Tilemap-ScriptableTiles-Example.html They mention setting TileFlags on the TileData to allow transformations from code that override the brush/user set rotations. Code (CSharp): tileData.flags = TileFlags.LockTransform; Also just fyi you can call SetTRS directly on the "tileData.transform" since it is a Matrix4x4. Hope that helps.
I tested both of those and neither did anything. I wonder if Unity even tests the examples they put up. They probably only work that way in the editor, not programmatically like I'm doing things. Thanks for the answer, nonetheless!
Try downloading the tech demos project and exploring their working examples: https://github.com/Unity-Technologies/2d-extras https://github.com/Unity-Technologies/2d-techdemos
I just found the same thing in the current unity version. I'm using code very similar to the example here: https://docs.unity3d.com/Manual/Tilemap-ScriptableTiles-Example.html
Just wanted to bump this as it is still an issue. I have the same code running as in the scriptable tiles example and I'm not getting any rotation at anytime. Runtime nor in the editor. Has anyone found anything else on it?
The code in https://docs.unity3d.com/Manual/Tilemap-ScriptableTiles-Example.html is slightly outdated and we are working in updating the code. The correct implementation should be Code (CSharp): var m = tileData.transform; m.SetTRS(Vector3.zero, GetRotation((byte) mask), Vector3.one); m = tileData.transform;
Just to throw in my experience. I was trying to rotate all tiles on a Tilemap by using the Custom orientation. I wanted them to billboard so that they were always facing the camera (using a 'perspective' camera that can pan and orbit similar to the camera in editor). The idea was to get a sort of pop-up book effect. I was able to accomplish that with this: Code (CSharp): Quaternion testq = Quaternion.Euler( Camera.main.transform.eulerAngles.x, Camera.main.transform.eulerAngles.y, Camera.main.transform.eulerAngles.z); var m = Matrix4x4.TRS(Vector3.zero, testq, Vector3.one); tileMap.orientation = Tilemap.Orientation.Custom; tileMap.orientationMatrix = m; I know this isn't exactly what you were trying to do, but there aren't many posts related to the matter, so I thought I would drop it here.
added random flipping and rotating and box and flood fill to random brush Code (CSharp): using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Tilemaps; namespace UnityEditor { [Flags] public enum FlipFlags { None = 0, FlipX = 1, FlipY = (1 << 1), Rot90 = (1 << 2), } [CreateAssetMenu] [CustomGridBrush(false, true, false, "Random Brush")] public class RandomBrush : GridBrush { public FlipFlags flipFlags = FlipFlags.None; public bool flipX { get { return (flipFlags & FlipFlags.FlipX) == FlipFlags.FlipX ? UnityEngine.Random.value > .5f : false; } } public bool flipY { get { return (flipFlags & FlipFlags.FlipY) == FlipFlags.FlipY ? UnityEngine.Random.value > .5f : false; } } public bool rot90 { get { return (flipFlags & FlipFlags.Rot90) == FlipFlags.Rot90 ? UnityEngine.Random.value > .5f : false; } } public TileBase[] randomTiles; public TileBase randomTile { get { return randomTiles[(int)(randomTiles.Length * UnityEngine.Random.value)]; } } public override void Paint(GridLayout gridLayout, GameObject targetBrush, Vector3Int position) { if (randomTiles != null && randomTiles.Length > 0) Common(gridLayout, targetBrush, position); } public override void BoxFill(GridLayout gridLayout, GameObject targetBrush, BoundsInt position) { if (randomTiles != null && randomTiles.Length > 0) foreach (var i in position.allPositionsWithin) Common(gridLayout, targetBrush, i); } public override void FloodFill(GridLayout gridLayout, GameObject targetBrush, Vector3Int position) { if (randomTiles != null && randomTiles.Length > 0) { if (targetBrush == null) return; var map = targetBrush.GetComponent<Tilemap>(); if (map == null) return; FloodFill(map, gridLayout, targetBrush, position); } } private void FloodFill(Tilemap map, GridLayout gridLayout, GameObject targetBrush, Vector3Int position) { var exist = map.GetTile(position); var points = new Stack<Vector3Int>(); points.Push(position); while (points.Count > 0) { var p = points.Pop(); Common(map, gridLayout, targetBrush, p); for (var y = p.y - 1; y <= p.y + 1; y++) { for (var x = p.x - 1; x <= p.x + 1; x++) { var test = new Vector3Int(x, y, p.z); if ((test.y != p.y || test.x != p.x) && map.cellBounds.Contains(test) && (exist ? map.GetTile(test) : !map.GetTile(test))) points.Push(test); } } } } private void Common(GridLayout gridLayout, GameObject targetBrush, Vector3Int position) { if (targetBrush == null) return; var map = targetBrush.GetComponent<Tilemap>(); if (map == null) return; Common(map, gridLayout, targetBrush, position); } private void Common(Tilemap map, GridLayout gridLayout, GameObject targetBrush, Vector3Int position) { map.SetTile(position, randomTile); map.SetTransformMatrix(position, Matrix4x4.TRS(Vector2.zero, rot90 ? Quaternion.Euler(0, 0, 90f) : Quaternion.identity, new Vector3(flipX ? -1f : 1f, flipY ? -1f : 1f, 1f))); } } [CustomEditor(typeof(RandomBrush))] public class RandomBrushEditor : GridBrushEditor { private RandomBrush randomBrush { get { return target as RandomBrush; } } private GameObject lastBrush; public override void PaintPreview(GridLayout gridLayout, GameObject targetBrush, Vector3Int position) { if (randomBrush.randomTiles != null && randomBrush.randomTiles.Length > 0) Common(gridLayout, targetBrush, position); } public override void BoxFillPreview(GridLayout gridLayout, GameObject targetBrush, BoundsInt position) { if (randomBrush.randomTiles != null && randomBrush.randomTiles.Length > 0) foreach (var i in position.allPositionsWithin) Common(gridLayout, targetBrush, i); } public override void FloodFillPreview(GridLayout gridLayout, GameObject targetBrush, Vector3Int position) { if (randomBrush.randomTiles != null && randomBrush.randomTiles.Length > 0) { if (targetBrush == null) return; var map = targetBrush.GetComponent<Tilemap>(); if (map == null) return; FloodFillTest(map, gridLayout, targetBrush, position); } } private void FloodFillTest(Tilemap map, GridLayout gridLayout, GameObject targetBrush, Vector3Int position) { var exist = map.GetTile(position); var points = new Stack<Vector3Int>(); points.Push(position); while (points.Count > 0) { var p = points.Pop(); Common(map, gridLayout, targetBrush, p); for (var y = p.y - 1; y <= p.y + 1; y++) { for (var x = p.x - 1; x <= p.x + 1; x++) { var test = new Vector3Int(x, y, p.z); if ((test.y != p.y || test.x != p.x) && map.cellBounds.Contains(test) && (exist ? map.GetTile(test) : !map.GetTile(test)) && !map.GetEditorPreviewTile(test)) points.Push(test); } } } } private void Common(GridLayout gridLayout, GameObject targetBrush, Vector3Int position) { if (targetBrush == null) return; var map = targetBrush.GetComponent<Tilemap>(); if (map == null) return; Common(map, gridLayout, targetBrush, position); } private void Common(Tilemap map, GridLayout gridLayout, GameObject targetBrush, Vector3Int position) { map.SetEditorPreviewTile(position, randomBrush.randomTile); map.SetEditorPreviewTransformMatrix(position, Matrix4x4.TRS(Vector2.zero, randomBrush.rot90 ? Quaternion.Euler(0, 0, 90f) : Quaternion.identity, new Vector3(randomBrush.flipX ? -1f : 1f, randomBrush.flipY ? -1f : 1f, 1f))); lastBrush = targetBrush; } public override void ClearPreview() { if (lastBrush != null) { var map = lastBrush.GetComponent<Tilemap>(); if (map == null) return; map.ClearAllEditorPreviewTiles(); lastBrush = null; } else base.ClearPreview(); } public override void OnPaintInspectorGUI() { GUI(); } public override void OnInspectorGUI() { GUI(); } private void GUI() { EditorGUI.BeginChangeCheck(); randomBrush.flipFlags = (FlipFlags)EditorGUILayout.EnumFlagsField("Flags", randomBrush.flipFlags); EditorGUILayout.PropertyField(serializedObject.FindProperty("randomTiles"), new GUIContent("Tiles"), true); if (EditorGUI.EndChangeCheck()) EditorUtility.SetDirty(randomBrush); } } }
Anybody has worked it out ? Iam at the same point. I want to rotate a prefab that instanced with a scriptabletile from code. But i cant cahnge the rotation after Startup. I can rotate it on StartUp, but after that i have no idea how to manipulate the rotation of the gameobject created by the tile. How can i change the rotation in RefreshTile for example ? Edit: I found a solution in this thread: https://forum.unity.com/threads/can...antiated-go-when-placing-tile-on-grid.536194/
It's easy to rotate the tile on tilemap. Just use Tilemap.SetTransformMatrix Here is the code: Code (CSharp): private void SetTile(Vector3Int pos, Quaternion rot, Tilemap tilemap, TileBase tile) { tilemap.SetTile(pos, tile); tilemap.SetTransformMatrix(pos, Matrix4x4.TRS(Vector3.zero, rot, Vector3.one)); }
You Sir are my Hero If you want to copy for example a tile from a Tilemap to another Tilemap and also want to take the rotation information with you then it will look like this Code (CSharp): var pos = new Vector3Int(tileXCoordinate, tileYCoordinate, 0); myTargetTilemap.SetTile(pos, mySourceTilemap.GetTile(pos)); myTargetTilemap.SetTransformMatrix(pos, Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f,0f, mySourceTilemap.GetTransformMatrix(pos).rotation.eulerAngles.z), Vector3.one));