Example #1
0
        public override uint[] GetSubtiles(Tilemap tilemap, int gridX, int gridY, uint tileData)
        {
            if (System.Array.IndexOf(TileIds, Tileset.k_TileData_Empty) >= 0)
            {
                return(null);
            }

            int brushId   = (int)((tileData & Tileset.k_TileDataMask_BrushId) >> 16);
            int brushId_N = (int)((uint)(tilemap.GetTileData(gridX, gridY + 1) & Tileset.k_TileDataMask_BrushId) >> 16);
            int brushId_E = (int)((uint)(tilemap.GetTileData(gridX + 1, gridY) & Tileset.k_TileDataMask_BrushId) >> 16);
            int brushId_S = (int)((uint)(tilemap.GetTileData(gridX, gridY - 1) & Tileset.k_TileDataMask_BrushId) >> 16);
            int brushId_W = (int)((uint)(tilemap.GetTileData(gridX - 1, gridY) & Tileset.k_TileDataMask_BrushId) >> 16);

            // diagonals
            int brushId_NE = (int)((uint)(tilemap.GetTileData(gridX + 1, gridY + 1) & Tileset.k_TileDataMask_BrushId) >> 16);
            int brushId_SE = (int)((uint)(tilemap.GetTileData(gridX + 1, gridY - 1) & Tileset.k_TileDataMask_BrushId) >> 16);
            int brushId_SW = (int)((uint)(tilemap.GetTileData(gridX - 1, gridY - 1) & Tileset.k_TileDataMask_BrushId) >> 16);
            int brushId_NW = (int)((uint)(tilemap.GetTileData(gridX - 1, gridY + 1) & Tileset.k_TileDataMask_BrushId) >> 16);

            uint[] subTileData = new uint[4];
            subTileData[0] = (AutotileWith(brushId, brushId_SW) && AutotileWith(brushId, brushId_S) && AutotileWith(brushId, brushId_W)) ? TileIds[3] : TileIds[0];
            subTileData[1] = (AutotileWith(brushId, brushId_SE) && AutotileWith(brushId, brushId_S) && AutotileWith(brushId, brushId_E)) ? TileIds[2] : TileIds[1];
            subTileData[2] = (AutotileWith(brushId, brushId_NW) && AutotileWith(brushId, brushId_N) && AutotileWith(brushId, brushId_W)) ? TileIds[1] : TileIds[2];
            subTileData[3] = (AutotileWith(brushId, brushId_NE) && AutotileWith(brushId, brushId_N) && AutotileWith(brushId, brushId_E)) ? TileIds[0] : TileIds[3];

            return(subTileData);
        }
Example #2
0
        private void CalculateNeighbourData(Tilemap tilemap, int gridX, int gridY, uint tileData)
        {
            s_needsSubTiles = false;
            s_brushId       = (int)((tileData & Tileset.k_TileDataMask_BrushId) >> 16);
            int brushId_N = (int)((uint)(tilemap.GetTileData(gridX, gridY + 1) & Tileset.k_TileDataMask_BrushId) >> 16);
            int brushId_E = (int)((uint)(tilemap.GetTileData(gridX + 1, gridY) & Tileset.k_TileDataMask_BrushId) >> 16);
            int brushId_S = (int)((uint)(tilemap.GetTileData(gridX, gridY - 1) & Tileset.k_TileDataMask_BrushId) >> 16);
            int brushId_W = (int)((uint)(tilemap.GetTileData(gridX - 1, gridY) & Tileset.k_TileDataMask_BrushId) >> 16);

            s_neighIdx = 0;
            if (AutotileWith(s_brushId, brushId_N))
            {
                s_neighIdx |= 1;
            }
            if (AutotileWith(s_brushId, brushId_E))
            {
                s_neighIdx |= 2;
            }
            if (AutotileWith(s_brushId, brushId_S))
            {
                s_neighIdx |= 4;
            }
            if (AutotileWith(s_brushId, brushId_W))
            {
                s_neighIdx |= 8;
            }

            s_needsSubTiles = (s_neighIdx == 0 || s_neighIdx == 1 || s_neighIdx == 2 || s_neighIdx == 4 ||
                               s_neighIdx == 5 || s_neighIdx == 8 || s_neighIdx == 10);

            // diagonals
            {
                int brushId_NE = (int)((uint)(tilemap.GetTileData(gridX + 1, gridY + 1) & Tileset.k_TileDataMask_BrushId) >> 16);
                int brushId_SE = (int)((uint)(tilemap.GetTileData(gridX + 1, gridY - 1) & Tileset.k_TileDataMask_BrushId) >> 16);
                int brushId_SW = (int)((uint)(tilemap.GetTileData(gridX - 1, gridY - 1) & Tileset.k_TileDataMask_BrushId) >> 16);
                int brushId_NW = (int)((uint)(tilemap.GetTileData(gridX - 1, gridY + 1) & Tileset.k_TileDataMask_BrushId) >> 16);

                s_showDiagonal[0] = !AutotileWith(s_brushId, brushId_SW) && AutotileWith(s_brushId, brushId_S) && AutotileWith(s_brushId, brushId_W);
                s_showDiagonal[1] = !AutotileWith(s_brushId, brushId_SE) && AutotileWith(s_brushId, brushId_S) && AutotileWith(s_brushId, brushId_E);
                s_showDiagonal[2] = !AutotileWith(s_brushId, brushId_NW) && AutotileWith(s_brushId, brushId_N) && AutotileWith(s_brushId, brushId_W);
                s_showDiagonal[3] = !AutotileWith(s_brushId, brushId_NE) && AutotileWith(s_brushId, brushId_N) && AutotileWith(s_brushId, brushId_E);

                s_tileData = TileIds[s_neighIdx];
                bool foundTrueDiagonal = false;
                for (int i = 0; !s_needsSubTiles && i < s_showDiagonal.Length; ++i)
                {
                    if (s_showDiagonal[i])
                    {
                        // if only a diagonal is true and it's surrounded by tiles s_neighIdx == 15, we don't need subtiles, instead the right corner tile will be taken
                        s_needsSubTiles   = foundTrueDiagonal || s_neighIdx != 15;
                        foundTrueDiagonal = true;
                        if (!s_needsSubTiles)
                        {
                            s_tileData = InteriorCornerTileIds[InteriorCornerTileIds.Length - i - 1];
                        }
                    }
                }
            }
        }
Example #3
0
        public void Paint(Tilemap tilemap, Vector2 localPos)
        {
            int minGridX = m_brushTilemap.MinGridX;
            int minGridY = m_brushTilemap.MinGridY;
            int maxGridX = m_brushTilemap.MaxGridX;
            int maxGridY = m_brushTilemap.MaxGridY;

            if (IsUndoEnabled)
            {
#if UNITY_EDITOR
                Undo.RecordObject(tilemap, Tilemap.k_UndoOpName + tilemap.name);
                Undo.RecordObjects(tilemap.GetComponentsInChildren <TilemapChunk>(), Tilemap.k_UndoOpName + tilemap.name);
#endif
            }
            tilemap.IsUndoEnabled = IsUndoEnabled;
            int dstGy = BrushUtil.GetGridY(localPos, tilemap.CellSize);
            for (int gridY = minGridY; gridY <= maxGridY; ++gridY, ++dstGy)
            {
                int dstGx = BrushUtil.GetGridX(localPos, tilemap.CellSize);
                for (int gridX = minGridX; gridX <= maxGridX; ++gridX, ++dstGx)
                {
                    uint tileData = m_brushTilemap.GetTileData(gridX, gridY);
                    if (
                        tileData != Tileset.k_TileData_Empty || // don't copy empty tiles
                        m_brushTilemap.GridWidth == 1 && m_brushTilemap.GridHeight == 1    // unless the brush size is one
                        )
                    {
                        tilemap.SetTileData(dstGx, dstGy, tileData);
                    }
                }
            }
            tilemap.UpdateMeshImmediate();
            tilemap.IsUndoEnabled = false;
        }
Example #4
0
        public bool AutotileWith(Tilemap tilemap, int selfBrushId, int gridX, int gridY)
        {
            bool isOutOfBounds = gridX > tilemap.MaxGridX || gridX <tilemap.MinGridX || gridY> tilemap.MaxGridY || gridY < tilemap.MinGridY;

            if ((AutotilingMode & eAutotilingMode.TilemapBounds) != 0 && isOutOfBounds)
            {
                return(true);
            }

            uint otherTileData = tilemap.GetTileData(gridX, gridY);

            if ((AutotilingMode & eAutotilingMode.EmptyCells) != 0 && otherTileData == Tileset.k_TileData_Empty)
            {
                return(true);
            }
            if ((AutotilingMode & eAutotilingMode.Group) != 0)
            {
                Tile tile = tilemap.Tileset.GetTile((int)(otherTileData & Tileset.k_TileDataMask_TileId));
                if (tile != null && Tileset.GetGroupAutotiling(Group, tile.autilingGroup))
                {
                    return(true);
                }
            }
            int otherBrushId = (int)((uint)(otherTileData & Tileset.k_TileDataMask_BrushId) >> 16);

            return(AutotileWith(selfBrushId, otherBrushId));
        }
Example #5
0
 public void CopyRect(Tilemap tilemap, int startGridX, int startGridY, int endGridX, int endGridY)
 {
     for (int gridY = startGridY; gridY <= endGridY; ++gridY)
     {
         for (int gridX = startGridX; gridX <= endGridX; ++gridX)
         {
             BrushTilemap.SetTileData(gridX - startGridX, gridY - startGridY, tilemap.GetTileData(gridX, gridY));
         }
     }
     BrushTilemap.UpdateMeshImmediate();
 }
Example #6
0
        public override uint Refresh(Tilemap tilemap, int gridX, int gridY, uint tileData)
        {
            int brushId       = (int)((tileData & Tileset.k_TileDataMask_BrushId) >> 16);
            int brushIdTop    = (int)((uint)(tilemap.GetTileData(gridX, gridY + 1) & Tileset.k_TileDataMask_BrushId) >> 16);
            int brushIdRight  = (int)((uint)(tilemap.GetTileData(gridX + 1, gridY) & Tileset.k_TileDataMask_BrushId) >> 16);
            int brushIdBottom = (int)((uint)(tilemap.GetTileData(gridX, gridY - 1) & Tileset.k_TileDataMask_BrushId) >> 16);
            int brushIdLeft   = (int)((uint)(tilemap.GetTileData(gridX - 1, gridY) & Tileset.k_TileDataMask_BrushId) >> 16);

            int idx = 0;

            if (AutotileWith(brushId, brushIdTop))
            {
                idx = 1;
            }
            if (AutotileWith(brushId, brushIdRight))
            {
                idx |= 2;
            }
            if (AutotileWith(brushId, brushIdBottom))
            {
                idx |= 4;
            }
            if (AutotileWith(brushId, brushIdLeft))
            {
                idx |= 8;
            }

            uint brushTileData = RefreshLinkedBrush(tilemap, gridX, gridY, TileIds[idx]);

            // overwrite flags
            brushTileData &= ~Tileset.k_TileDataMask_Flags;
            brushTileData |= TileIds[idx] & Tileset.k_TileDataMask_Flags;
            // overwrite brush id
            brushTileData &= ~Tileset.k_TileDataMask_BrushId;
            brushTileData |= tileData & Tileset.k_TileDataMask_BrushId;
            return(brushTileData);
        }
Example #7
0
 /// <summary>
 /// Iterate through all the tilemap cells and calls an action for each cell.
 /// Ex:
 /// void EraseTilesFromTilemap(Tilemap tilemap)
 /// {
 ///    IterateTilemapWithAction(tilemap, EraseTilesAction);
 /// }
 /// void EraseTilesAction(Tilemap tilemap, int gx, int gy)
 /// {
 ///    tilemap.Erase(gx, gy);
 /// }
 /// </summary>
 /// <param name="tilemap"></param>
 /// <param name="action"></param>
 static public void IterateTilemapWithAction(Tilemap tilemap, System.Action <Tilemap, int, int, uint> action)
 {
     if (tilemap)
     {
         for (int gy = tilemap.MinGridY; gy <= tilemap.MaxGridY; ++gy)
         {
             for (int gx = tilemap.MinGridX; gx <= tilemap.MaxGridX; ++gx)
             {
                 if (action != null)
                 {
                     action(tilemap, gx, gy, tilemap.GetTileData(gx, gy));
                 }
             }
         }
     }
 }
Example #8
0
        public void CutRect(Tilemap tilemap, int startGridX, int startGridY, int endGridX, int endGridY)
        {
            if (IsUndoEnabled)
            {
#if UNITY_EDITOR
                Undo.RecordObject(tilemap, Tilemap.k_UndoOpName + tilemap.name);
                Undo.RecordObjects(tilemap.GetComponentsInChildren <TilemapChunk>(), Tilemap.k_UndoOpName + tilemap.name);
#endif
            }
            tilemap.IsUndoEnabled = IsUndoEnabled;

            for (int gridY = startGridY; gridY <= endGridY; ++gridY)
            {
                for (int gridX = startGridX; gridX <= endGridX; ++gridX)
                {
                    BrushTilemap.SetTileData(gridX - startGridX, gridY - startGridY, tilemap.GetTileData(gridX, gridY));
                    tilemap.SetTileData(gridX, gridY, Tileset.k_TileData_Empty);
                }
            }
            BrushTilemap.UpdateMeshImmediate();
            tilemap.UpdateMeshImmediate();

            tilemap.IsUndoEnabled = false;
        }
Example #9
0
        private void DoPaintInspector()
        {
            Event e = Event.current;

            Tilemap tilemap = (Tilemap)target;

            if (DoToolBar() ||
                DragAndDrop.objectReferences.Length > 0 || // hide brush when user is dragging a prefab into the scene
                EditorWindow.mouseOverWindow != SceneView.currentDrawingSceneView)    // hide brush when it's not over the scene view
            {
                m_brushVisible = false;
                SceneView.RepaintAll();
                return;
            }

            int controlID = GUIUtility.GetControlID(FocusType.Passive);

            HandleUtility.AddDefaultControl(controlID);
            EventType currentEventType = Event.current.GetTypeForControl(controlID);
            bool      skip             = false;
            int       saveControl      = GUIUtility.hotControl;

            try
            {
                if (currentEventType == EventType.Layout)
                {
                    skip = true;
                }
                else if (currentEventType == EventType.ScrollWheel)
                {
                    skip = true;
                }

                if (tilemap.Tileset == null)
                {
                    return;
                }

                if (!skip)
                {
                    if (e.type == EventType.KeyDown)
                    {
                        if (e.keyCode == ShortcutKeys.k_FlipH)
                        {
                            BrushBehaviour.GetOrCreateBrush(tilemap).FlipH(!e.shift);
                            e.Use(); // Use key event
                        }
                        else if (e.keyCode == ShortcutKeys.k_FlipV)
                        {
                            BrushBehaviour.GetOrCreateBrush(tilemap).FlipV(!e.shift);
                            e.Use(); // Use key event
                        }
                        else if (e.keyCode == ShortcutKeys.k_Rot90)
                        {
                            BrushBehaviour.GetOrCreateBrush(tilemap).Rot90(!e.shift);
                            e.Use(); // Use key event
                        }
                        else if (e.keyCode == ShortcutKeys.k_Rot90Back)
                        {
                            BrushBehaviour.GetOrCreateBrush(tilemap).Rot90Back(!e.shift);
                            e.Use(); // Use key event
                        }
                    }

                    EditorGUIUtility.AddCursorRect(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), MouseCursor.Arrow);
                    GUIUtility.hotControl = controlID;
                    {
                        Plane   chunkPlane = new Plane(tilemap.transform.forward, tilemap.transform.position);
                        Vector2 mousePos   = Event.current.mousePosition; mousePos.y = Screen.height - mousePos.y;
                        Ray     ray        = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
                        float   dist;
                        if (chunkPlane.Raycast(ray, out dist))
                        {
                            Rect rTile = new Rect(0, 0, m_tilemap.CellSize.x, m_tilemap.CellSize.y);
                            rTile.position = tilemap.transform.InverseTransformPoint(ray.GetPoint(dist));

                            Vector2 tilePos = rTile.position;
                            if (tilePos.x < 0)
                            {
                                tilePos.x -= m_tilemap.CellSize.x;
                            }
                            if (tilePos.y < 0)
                            {
                                tilePos.y -= m_tilemap.CellSize.y;
                            }
                            tilePos.x     -= tilePos.x % m_tilemap.CellSize.x;
                            tilePos.y     -= tilePos.y % m_tilemap.CellSize.y;
                            rTile.position = tilePos;


                            Vector2 startPos            = new Vector2(Mathf.Min(m_startDragging.x, m_endDragging.x), Mathf.Min(m_startDragging.y, m_endDragging.y));
                            Vector2 endPos              = new Vector2(Mathf.Max(m_startDragging.x, m_endDragging.x), Mathf.Max(m_startDragging.y, m_endDragging.y));
                            Vector2 selectionSnappedPos = BrushUtil.GetSnappedPosition(startPos, m_tilemap.CellSize);
                            Vector2 selectionSize       = BrushUtil.GetSnappedPosition(endPos, m_tilemap.CellSize) - selectionSnappedPos + m_tilemap.CellSize;

                            BrushBehaviour brush = BrushBehaviour.GetOrCreateBrush(tilemap);
                            // Update brush transform
                            m_localPaintPos = (Vector2)tilemap.transform.InverseTransformPoint(ray.GetPoint(dist));
                            Vector2 brushSnappedPos = BrushUtil.GetSnappedPosition(brush.Offset + m_localPaintPos, m_tilemap.CellSize);
                            brush.transform.rotation   = tilemap.transform.rotation;
                            brush.transform.localScale = tilemap.transform.lossyScale;
                            brush.transform.position   = tilemap.transform.TransformPoint(new Vector3(brushSnappedPos.x, brushSnappedPos.y, -0.01f));
                            //---

                            int prevMouseGridX = m_mouseGridX;
                            int prevMouseGridY = m_mouseGridY;
                            if (e.isMouse)
                            {
                                m_mouseGridX = BrushUtil.GetGridX(m_localPaintPos, tilemap.CellSize);
                                m_mouseGridY = BrushUtil.GetGridY(m_localPaintPos, tilemap.CellSize);
                            }
                            bool isMouseGridChanged = prevMouseGridX != m_mouseGridX || prevMouseGridY != m_mouseGridY;
                            //Update Fill Preview
                            if (GetBrushMode() == eBrushMode.Fill && isMouseGridChanged)
                            {
                                m_fillPreview.Clear();
                                TilemapDrawingUtils.FloodFillPreview(tilemap, brush.Offset + m_localPaintPos, brush.BrushTilemap.GetTileData(0, 0), m_fillPreview);
                            }

                            if (
                                (EditorWindow.focusedWindow == EditorWindow.mouseOverWindow) && // fix painting tiles when closing another window popup over the SceneView like GameObject Selection window
                                (e.type == EventType.MouseDown || e.type == EventType.MouseDrag && isMouseGridChanged)
                                )
                            {
                                if (e.button == 0)
                                {
                                    if (m_dblClick.IsDblClick && brush.BrushTilemap.GridWidth == 1 && brush.BrushTilemap.GridHeight == 1)
                                    {
                                        // Restore previous tiledata modified by Paint, because before the double click, a single click is done before
                                        tilemap.SetTileData(brush.Offset + m_localPaintPos, m_floodFillRestoredTileData);
                                        brush.FloodFill(tilemap, brush.Offset + m_localPaintPos, brush.BrushTilemap.GetTileData(0, 0));
                                    }
                                    // Do a brush paint action
                                    else
                                    {
                                        switch (GetBrushMode())
                                        {
                                        case eBrushMode.Paint:
                                            m_floodFillRestoredTileData = tilemap.GetTileData(m_mouseGridX, m_mouseGridY);
                                            brush.Paint(tilemap, brush.Offset + m_localPaintPos);
                                            break;

                                        case eBrushMode.Erase:
                                            brush.Erase(tilemap, brush.Offset + m_localPaintPos);
                                            break;

                                        case eBrushMode.Fill:
                                            brush.FloodFill(tilemap, brush.Offset + m_localPaintPos, brush.BrushTilemap.GetTileData(0, 0));
                                            break;
                                        }
                                    }
                                }
                                else if (e.button == 1)
                                {
                                    if (e.type == EventType.MouseDown)
                                    {
                                        m_isDragging = true;
                                        brush.BrushTilemap.ClearMap();
                                        m_startDragging = m_endDragging = m_localPaintPos;
                                    }
                                    else
                                    {
                                        m_endDragging = m_localPaintPos;
                                    }
                                }
                            }
                            else if (e.type == EventType.MouseUp)
                            {
                                if (e.button == 1) // right mouse button
                                {
                                    m_isDragging = false;
                                    ResetBrushMode();
                                    // Copy one tile
                                    if (selectionSize.x <= m_tilemap.CellSize.x && selectionSize.y <= m_tilemap.CellSize.y)
                                    {
                                        uint tileData = tilemap.GetTileData(m_localPaintPos);
                                        if (tileData == Tileset.k_TileData_Empty)
                                        {
                                            tilemap.Tileset.SelectedTileId = Tileset.k_TileId_Empty;
                                            brush.BrushTilemap.SetTileData(0, 0, Tileset.k_TileData_Empty);
                                        }
                                        else
                                        {
                                            int brushId = Tileset.GetBrushIdFromTileData(tileData);
                                            int tileId  = Tileset.GetTileIdFromTileData(tileData);

                                            // Select the copied tile in the tileset, alternating between the brush and the tile drawn by the brush
                                            if (brushId > 0 && brushId != tilemap.Tileset.SelectedBrushId)
                                            {
                                                tilemap.Tileset.SelectedBrushId = brushId;
                                            }
                                            else
                                            {
                                                tilemap.Tileset.SelectedTileId = tileId;
                                                brush.BrushTilemap.SetTileData(0, 0, tileData & ~Tileset.k_TileDataMask_BrushId); // keep tile flags
                                            }
                                        }

                                        // Cut tile if key shift is pressed
                                        if (e.shift)
                                        {
                                            int startGridX = BrushUtil.GetGridX(startPos, m_tilemap.CellSize);
                                            int startGridY = BrushUtil.GetGridY(startPos, m_tilemap.CellSize);
                                            brush.CutRect(tilemap, startGridX, startGridY, startGridX, startGridY);
                                        }

                                        brush.BrushTilemap.UpdateMesh();
                                        brush.Offset = Vector2.zero;
                                    }
                                    // copy a rect of tiles
                                    else
                                    {
                                        int startGridX = BrushUtil.GetGridX(startPos, m_tilemap.CellSize);
                                        int startGridY = BrushUtil.GetGridY(startPos, m_tilemap.CellSize);
                                        int endGridX   = BrushUtil.GetGridX(endPos, m_tilemap.CellSize);
                                        int endGridY   = BrushUtil.GetGridY(endPos, m_tilemap.CellSize);

                                        // Cut tile if key shift is pressed
                                        if (e.shift)
                                        {
                                            brush.CutRect(tilemap, startGridX, startGridY, endGridX, endGridY);
                                        }
                                        else
                                        {
                                            brush.CopyRect(tilemap, startGridX, startGridY, endGridX, endGridY);
                                        }
                                        brush.Offset.x = m_endDragging.x > m_startDragging.x ? -(endGridX - startGridX) * tilemap.CellSize.x : 0f;
                                        brush.Offset.y = m_endDragging.y > m_startDragging.y ? -(endGridY - startGridY) * tilemap.CellSize.y : 0f;
                                    }
                                }
                            }

                            if (m_isDragging)
                            {
                                Rect rGizmo = new Rect(selectionSnappedPos, selectionSize);
                                HandlesEx.DrawRectWithOutline(tilemap.transform, rGizmo, new Color(), Color.white);
                            }
                            else // Draw brush border
                            {
                                Rect  rBound = new Rect(brush.BrushTilemap.MapBounds.min, brush.BrushTilemap.MapBounds.size);
                                Color fillColor;
                                switch (GetBrushMode())
                                {
                                case eBrushMode.Paint:
                                    fillColor = new Color(0, 0, 0, 0);
                                    break;

                                case eBrushMode.Erase:
                                    fillColor = new Color(1f, 0f, 0f, 0.1f);
                                    break;

                                case eBrushMode.Fill:
                                    fillColor = new Color(1f, 1f, 0f, 0.2f);
                                    break;

                                default:
                                    fillColor = new Color(0, 0, 0, 0);
                                    break;
                                }
                                HandlesEx.DrawRectWithOutline(brush.transform, rBound, fillColor, new Color(1, 1, 1, 0.2f));
                            }
                        }
                    }

                    if (currentEventType == EventType.MouseDrag && Event.current.button < 2) // 2 is for central mouse button
                    {
                        // avoid dragging the map
                        Event.current.Use();
                    }
                }
            }
            // Avoid loosing the hotControl because of a triggered exception
            catch (System.Exception ex)
            {
                Debug.LogException(ex);
            }

            SceneView.RepaintAll();
            GUIUtility.hotControl = saveControl;
        }
Example #10
0
        public void SetTileData(int locGridX, int locGridY, uint tileData)
        {
            if (locGridX >= 0 && locGridX < m_width && locGridY >= 0 && locGridY < m_height)
            {
                int tileIdx = locGridY * m_width + locGridX;

                int  tileId = (int)(tileData & Tileset.k_TileDataMask_TileId);
                Tile tile   = tileId != Tileset.k_TileId_Empty? Tileset.Tiles[tileId] : null;

                int  prevTileId = (int)(m_tileDataList[tileIdx] & Tileset.k_TileDataMask_TileId);
                Tile prevTile   = prevTileId != Tileset.k_TileId_Empty? Tileset.Tiles[prevTileId] : null;

                int brushId     = Tileset.GetBrushIdFromTileData(tileData);
                int prevBrushId = Tileset.GetBrushIdFromTileData(m_tileDataList[tileIdx]);

                if (brushId != prevBrushId)
                {
                    TilesetBrush brush     = ParentTilemap.Tileset.FindBrush(brushId);
                    TilesetBrush prevBrush = ParentTilemap.Tileset.FindBrush(prevBrushId);
                    if (prevBrush != null)
                    {
                        prevBrush.OnErase(this, locGridX, locGridY, tileData);
                    }
                    if (brush != null)
                    {
                        tileData = brush.OnPaint(this, locGridX, locGridY, tileData);
                    }

                    // Refresh Neighbors ( and itself if needed )
                    for (int yf = -1; yf <= 1; ++yf)
                    {
                        for (int xf = -1; xf <= 1; ++xf)
                        {
                            if ((xf | yf) == 0)
                            {
                                if (brushId > 0)
                                {
                                    // Refresh itself
                                    tileData = (tileData & ~Tileset.k_TileFlag_Updated);
                                }
                            }
                            else
                            {
                                int          gx               = (locGridX + xf);
                                int          gy               = (locGridY + yf);
                                int          idx              = gy * m_width + gx;
                                bool         isInsideChunk    = (gx >= 0 && gx < m_width && gy >= 0 && gy < m_height);
                                uint         neighborTileData = isInsideChunk ? m_tileDataList[idx] : ParentTilemap.GetTileData(GridPosX + locGridX + xf, GridPosY + locGridY + yf);
                                int          neighborBrushId  = (int)((neighborTileData & Tileset.k_TileDataMask_BrushId) >> 16);
                                TilesetBrush neighborBrush    = ParentTilemap.Tileset.FindBrush(neighborBrushId);
                                //if (brush != null && brush.AutotileWith(brushId, neighborBrushId) || prevBrush != null && prevBrush.AutotileWith(prevBrushId, neighborBrushId))
                                if (neighborBrush != null &&
                                    (neighborBrush.AutotileWith(neighborBrushId, brushId) || neighborBrush.AutotileWith(neighborBrushId, prevBrushId)))
                                {
                                    neighborTileData = (neighborTileData & ~Tileset.k_TileFlag_Updated); // force a refresh
                                    if (isInsideChunk)
                                    {
                                        m_tileDataList[idx] = neighborTileData;
                                    }
                                    else
                                    {
                                        ParentTilemap.SetTileData(GridPosX + gx, GridPosY + gy, neighborTileData);
                                    }
                                }
                            }
                        }
                    }
                }
                else if (brushId > 0)
                {
                    // Refresh itself
                    tileData = (tileData & ~Tileset.k_TileFlag_Updated);
                }

                m_needsRebuildMesh      |= (m_tileDataList[tileIdx] != tileData) || (tileData & Tileset.k_TileDataMask_TileId) == Tileset.k_TileId_Empty;
                m_needsRebuildColliders |= m_needsRebuildMesh &&
                                           (
                    (prevBrushId > 0) || (brushId > 0) || // there is a brush (a brush could change the collider data later)
                    (tile != null && tile.collData.type != eTileCollider.None) || (prevTile != null && prevTile.collData.type != eTileCollider.None)    // prev. or new tile has colliders
                                           );

                if (ParentTilemap.ColliderType != eColliderType.None && m_needsRebuildColliders)
                {
                    // Refresh Neighbors tilechunk colliders, to make the collider autotiling
                    // Only if neighbor is outside this tilechunk
                    for (int yf = -1; yf <= 1; ++yf)
                    {
                        for (int xf = -1; xf <= 1; ++xf)
                        {
                            if ((xf | yf) != 0) // skip this tile position xf = yf = 0
                            {
                                int  gx            = (locGridX + xf);
                                int  gy            = (locGridY + yf);
                                bool isInsideChunk = (gx >= 0 && gx < m_width && gy >= 0 && gy < m_height);
                                if (!isInsideChunk)
                                {
                                    ParentTilemap.InvalidateChunkAt(GridPosX + gx, GridPosY + gy, false, true);
                                }
                            }
                        }
                    }
                }

                // Update tile data
                m_tileDataList[tileIdx] = tileData;

                if (!Tilemap.DisableTilePrefabCreation)
                {
                    // Create tile Objects
                    if (tile != null && tile.prefabData.prefab != null)
                    {
                        CreateTileObject(tileIdx, tile.prefabData);
                    }
                    else
                    {
                        DestroyTileObject(tileIdx);
                    }
                }
            }
        }
        //https://social.msdn.microsoft.com/Forums/en-US/9d926a16-0051-4ca3-b77c-8095fb489ae2/flood-fill-c?forum=csharplanguage
        public static void FloodFill(Tilemap tilemap, int gridX, int gridY, uint[,] tileData)
        {
            float timeStamp;

            timeStamp = Time.realtimeSinceStartup;
            //float callTimeStamp = timeStamp;

            int patternW             = tileData.GetLength(0);
            int patternH             = tileData.GetLength(1);
            LinkedList <Point> check = new LinkedList <Point>();
            uint floodFrom           = tilemap.GetTileData(gridX, gridY);

            tilemap.SetTileData(gridX, gridY, tileData[(gridX % patternW + patternW) % patternW, (gridY % patternH + patternH) % patternH]);
            bool isBrush = Tileset.GetBrushIdFromTileData(floodFrom) != 0;

            //Debug.Log(" Flood Fill Starts +++++++++++++++ ");
            if (
                (patternW > 0 && patternH > 0) &&
                isBrush?
                Tileset.GetBrushIdFromTileData(floodFrom) != Tileset.GetBrushIdFromTileData(tileData[0, 0])
                :
                floodFrom != tileData[0, 0]
                )
            {
                check.AddLast(new Point(gridX, gridY));
                while (check.Count > 0)
                {
                    Point cur = check.First.Value;
                    check.RemoveFirst();

                    foreach (Point off in new Point[] {
                        new Point(0, -1), new Point(0, 1),
                        new Point(-1, 0), new Point(1, 0)
                    })
                    {
                        Point next         = new Point(cur.X + off.X, cur.Y + off.Y);
                        uint  nextTileData = tilemap.GetTileData(next.X, next.Y);
                        if (
                            next.X >= tilemap.MinGridX && next.X <= tilemap.MaxGridX &&
                            next.Y >= tilemap.MinGridY && next.Y <= tilemap.MaxGridY
                            )
                        {
                            if (
                                isBrush?
                                Tileset.GetBrushIdFromTileData(floodFrom) == Tileset.GetBrushIdFromTileData(nextTileData)
                                :
                                floodFrom == nextTileData
                                )
                            {
                                check.AddLast(next);
                                tilemap.SetTileData(next.X, next.Y, tileData[(next.X % patternW + patternW) % patternW, (next.Y % patternH + patternH) % patternH]);
                            }
                        }
                    }

                    float timePast = Time.realtimeSinceStartup - timeStamp;
                    if (timePast > k_timeToAbortFloodFill)
                    {
#if UNITY_EDITOR
                        int result = UnityEditor.EditorUtility.DisplayDialogComplex("FloodFill is taking too much time", "Do you want to continue for another " + k_timeToAbortFloodFill + " seconds?", "Wait", "Cancel", "Wait and Don't ask again");
                        if (result == 0)
                        {
                            timeStamp = Time.realtimeSinceStartup;
                        }
                        else if (result == 1)
                        {
                            break;
                        }
                        else if (result == 2)
                        {
                            timeStamp = float.MaxValue;
                        }
#else
                        check.Clear();
#endif
                    }
                }
            }

            //Debug.Log("FloodFill Time " + (int)((Time.realtimeSinceStartup - callTimeStamp) * 1000) + "ms");
        }
        //Note: this is doing the same as FloodFill but not saving data in the tilemap, only saving the filled points and returning a list
        public static void FloodFillPreview(Tilemap tilemap, int gridX, int gridY, uint tileData, List <Vector2> outFilledPoints, uint maxPoints = uint.MaxValue)
        {
            if (
                gridX >= tilemap.MinGridX && gridX <= tilemap.MaxGridX &&
                gridY >= tilemap.MinGridY && gridY <= tilemap.MaxGridY
                )
            {
                bool[]             filledPoints = new bool[tilemap.GridWidth * tilemap.GridHeight];
                LinkedList <Point> check        = new LinkedList <Point>();
                uint floodFrom = tilemap.GetTileData(gridX, gridY);
                outFilledPoints.Add(Vector2.Scale(new Vector2(gridX, gridY), tilemap.CellSize));
                filledPoints[(gridY - tilemap.MinGridY) * tilemap.GridWidth + gridX - tilemap.MinGridX] = true;
                bool isBrush = Tileset.GetBrushIdFromTileData(floodFrom) != 0;
                if (
                    isBrush ?
                    Tileset.GetBrushIdFromTileData(floodFrom) != Tileset.GetBrushIdFromTileData(tileData)
                    :
                    floodFrom != tileData
                    )
                {
                    check.AddLast(new Point(gridX, gridY));
                    while (check.Count > 0)
                    {
                        Point cur = check.First.Value;
                        check.RemoveFirst();

                        foreach (Point off in new Point[] {
                            new Point(0, -1), new Point(0, 1),
                            new Point(-1, 0), new Point(1, 0)
                        })
                        {
                            Point next = new Point(cur.X + off.X, cur.Y + off.Y);

                            if (
                                next.X >= tilemap.MinGridX && next.X <= tilemap.MaxGridX &&
                                next.Y >= tilemap.MinGridY && next.Y <= tilemap.MaxGridY
                                )
                            {
                                if (filledPoints[(next.Y - tilemap.MinGridY) * tilemap.GridWidth + next.X - tilemap.MinGridX])
                                {
                                    continue;                                                                                            // skip already filled points
                                }
                                uint nextTileData = tilemap.GetTileData(next.X, next.Y);
                                if (
                                    isBrush ?
                                    Tileset.GetBrushIdFromTileData(floodFrom) == Tileset.GetBrushIdFromTileData(nextTileData)
                                    :
                                    floodFrom == nextTileData
                                    )
                                {
                                    check.AddLast(next);
                                    filledPoints[(next.Y - tilemap.MinGridY) * tilemap.GridWidth + next.X - tilemap.MinGridX] = true;
                                    outFilledPoints.Add(Vector2.Scale(new Vector2(next.X, next.Y), tilemap.CellSize));
                                    if (outFilledPoints.Count >= maxPoints)
                                    {
                                        return;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }