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); }
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]; } } } } }
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; }
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)); }
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(); }
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); }
/// <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)); } } } } }
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; }
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; }
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; } } } } } } } }