public void CutRect(STETilemap tilemap, int startGridX, int startGridY, int endGridX, int endGridY) { if (IsUndoEnabled) { #if UNITY_EDITOR Undo.RecordObject(tilemap, STETilemap.k_UndoOpName + tilemap.name); Undo.RecordObjects(tilemap.GetComponentsInChildren <TilemapChunk>(), STETilemap.k_UndoOpName + tilemap.name); #endif } tilemap.IsUndoEnabled = IsUndoEnabled; TileObjSourceTilemap = tilemap; TileObjSourceTilemapOffset = new Vector2Int(startGridX, startGridY); 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); } } TileObjSourceTilemap = null; BrushTilemap.UpdateMeshImmediate(); tilemap.UpdateMeshImmediate(); tilemap.IsUndoEnabled = false; }
public bool AutotileWith(STETilemap 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(STETilemap 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 bool AutotileWith(STETilemap 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); return(AutotileWith(tilemap.Tileset, selfBrushId, otherTileData)); }
public void InitializeGrid() { mapTiles.Clear(); for (int x = tilemap.MinGridX; x <= tilemap.MaxGridX; x++) { for (int y = tilemap.MinGridY; y <= tilemap.MaxGridY; y++) { Tile tileSTE = tilemap.GetTile(x, y); uint tileDataSTE = tilemap.GetTileData(x, y); uint dataSTE = Tileset.GetTileFlagsFromTileData(tileDataSTE); if (tileSTE == null) { continue; } LightTile tile = new LightTile(); tile.gridPosition = new Vector3Int(x, y, 0); tile.uv = tileSTE.uv; bool flipX = (dataSTE & k_TileFlag_FlipH) != 0; bool flipY = (dataSTE & k_TileFlag_FlipV) != 0; Vector2 scale = Vector2.one; if (flipX) { scale.x = -1; } if (flipY) { scale.y = -1; } tile.scale = scale; bool dynamic = this.shadowTypeSTE == SuperTilemapEditorSupport.TilemapCollider2D.ShadowType.TileCollider; if (dynamic) { List <Polygon2> polygons = TileColliderDataToPolygons(tileSTE.collData, tile.scale); if (polygons.Count > 0) { tile.SetLocalPolygons(polygons); } } mapTiles.Add(tile); } } }
public void CopyRect(STETilemap tilemap, int startGridX, int startGridY, int endGridX, int endGridY) { TileObjSourceTilemap = tilemap; TileObjSourceTilemapOffset = new Vector2Int(startGridX, startGridY); for (int gridY = startGridY; gridY <= endGridY; ++gridY) { for (int gridX = startGridX; gridX <= endGridX; ++gridX) { BrushTilemap.SetTileData(gridX - startGridX, gridY - startGridY, tilemap.GetTileData(gridX, gridY)); } } TileObjSourceTilemap = null; BrushTilemap.UpdateMeshImmediate(); }
/// <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(STETilemap tilemap, System.Action <STETilemap, 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 Paint(STETilemap tilemap, Vector2 localPos, bool skipEmptyTiles = false) { 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, STETilemap.k_UndoOpName + tilemap.name); Undo.RecordObjects(tilemap.GetComponentsInChildren <TilemapChunk>(), STETilemap.k_UndoOpName + tilemap.name); #endif } tilemap.IsUndoEnabled = IsUndoEnabled; int dstGy = BrushUtil.GetGridY(localPos, tilemap.CellSize); bool doPaintEmpty = m_brushTilemap.GridWidth == 1 && m_brushTilemap.GridHeight == 1 || // don't copy empty tiles m_brushPattern != null && m_brushPattern.GetLength(0) == 1 && m_brushPattern.GetLength(1) == 1;// unless the brush size is one doPaintEmpty &= !skipEmptyTiles; TileObjSourceTilemap = BrushTilemap; TileObjSourceTilemapOffset = new Vector2Int(-BrushUtil.GetGridX(localPos, tilemap.CellSize), -dstGy); 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 ( doPaintEmpty || tileData != Tileset.k_TileData_Empty ) { tilemap.SetTileData(dstGx, dstGy, tileData); } } } tilemap.UpdateMeshImmediate(); TileObjSourceTilemap = null; tilemap.IsUndoEnabled = false; }
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 = Tileset.GetTile(tileId); int prevTileId = (int)(m_tileDataList[tileIdx] & Tileset.k_TileDataMask_TileId); Tile prevTile = Tileset.GetTile(prevTileId); int brushId = Tileset.GetBrushIdFromTileData(tileData); int prevBrushId = Tileset.GetBrushIdFromTileData(m_tileDataList[tileIdx]); if (brushId != prevBrushId || brushId == 0) //NOTE: because of the autotiling mode, neighbour tiles could be affected by this change, even if the tile is not a brush { if (!s_currUpdatedTilechunk) // avoid this is chunks is being Updated from FillMeshData { // 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 (neighborBrush != null && (neighborBrush.AutotileWith(ParentTilemap.Tileset, neighborBrushId, tileData) || neighborBrush.AutotileWith(ParentTilemap.Tileset, neighborBrushId, m_tileDataList[tileIdx]))) { 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 (!STETilemap.DisableTilePrefabCreation) { // Create tile Objects if (tile != null && tile.prefabData.prefab != null) { CreateTileObject(tileIdx, tile.prefabData); } else { DestroyTileObject(tileIdx); } } TilesetBrush brush = ParentTilemap.Tileset.FindBrush(brushId); if (brushId != prevBrushId) { TilesetBrush prevBrush = ParentTilemap.Tileset.FindBrush(prevBrushId); if (prevBrush != null) { prevBrush.OnErase(this, locGridX, locGridY, tileData, prevBrushId); } } if (brush != null) { tileData = brush.OnPaint(this, locGridX, locGridY, tileData); } } }
//https://social.msdn.microsoft.com/Forums/en-US/9d926a16-0051-4ca3-b77c-8095fb489ae2/flood-fill-c?forum=csharplanguage public static void FloodFill(STETilemap tilemap, int gridX, int gridY, uint[,] tileData, bool randomize = false) { 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); int dataIdx0 = randomize ? Random.Range(0, patternW) : (gridX % patternW + patternW) % patternW; int dataIdx1 = randomize ? Random.Range(0, patternH) : (gridY % patternH + patternH) % patternH; tilemap.SetTileData(gridX, gridY, tileData[dataIdx0, dataIdx1]); 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); dataIdx0 = randomize ? Random.Range(0, patternW) : (next.X % patternW + patternW) % patternW; dataIdx1 = randomize ? Random.Range(0, patternH) : (next.Y % patternH + patternH) % patternH; tilemap.SetTileData(next.X, next.Y, tileData[dataIdx0, dataIdx1]); } } } 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(STETilemap 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; } } } } } } } }
static public T GetTileParameter <T>(STETilemap tilemap, int gridX, int gridY, string paramName, T defaultValue = default(T)) { return(GetTileParameter <T>(tilemap.Tileset, tilemap.GetTileData(gridX, gridY), paramName, defaultValue)); }
static public T GetTileParameter <T>(STETilemap tilemap, Vector2 locPosition, string paramName, T defaultValue = default(T)) { return(GetTileParameter <T>(tilemap.Tileset, tilemap.GetTileData(locPosition), paramName, defaultValue)); }