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) { 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 (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); } } 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); } } }
public static Vector2 SnapVertex(Vector2 vertex, Tileset tileset) { vertex.x = Mathf.Clamp01(Mathf.RoundToInt(vertex.x * tileset.TilePxSize.x) / tileset.TilePxSize.x); vertex.y = Mathf.Clamp01(Mathf.RoundToInt(vertex.y * tileset.TilePxSize.y) / tileset.TilePxSize.y); return(vertex); }
public override void OnEnable() { base.OnEnable(); m_brush = (RandomBrush)target; if (m_brush.Tileset != null) { m_brush.Tileset.OnTileSelected += OnTileSelected; m_brush.Tileset.OnBrushSelected += OnBrushSelected; } m_randTileList = new ReorderableList(serializedObject, serializedObject.FindProperty("RandomTileList"), true, true, true, true); // Fix: Issue in Unity 2019.4.1f1 m_randTileList.GrabKeyboardFocus(); randTileListControlId = GUIUtility.keyboardControl; //--- m_randTileList.drawHeaderCallback += (Rect rect) => { EditorGUI.LabelField(rect, "Random Tiles", EditorStyles.boldLabel); }; m_randTileList.drawElementCallback += (Rect rect, int index, bool isActive, bool isFocused) => { Rect rTile = rect; rTile.width = rTile.height = m_brush.Tileset.VisualTileSize.y; uint tileData = m_brush.RandomTileList[index].tileData; int tileId = (int)(tileData & Tileset.k_TileDataMask_TileId); int brushId = Tileset.GetBrushIdFromTileData(tileData); TilesetBrush brush = m_brush.Tileset.FindBrush(brushId); if (brush) { GUI.Box(new Rect(rTile.position - Vector2.one, rTile.size + 2 * Vector2.one), ""); TilesetEditor.DoGUIDrawTileFromTileData(rTile, tileData, m_brush.Tileset, brush.GetAnimUV()); } else if (tileId != Tileset.k_TileId_Empty) { GUI.Box(new Rect(rTile.position - Vector2.one, rTile.size + 2 * Vector2.one), ""); TilesetEditor.DoGUIDrawTileFromTileData(rTile, tileData, m_brush.Tileset); } Rect rTileId = rect; rTileId.x += rTile.width + 10; rTileId.width -= rTile.width + 20; rTileId.height = rect.height / 2; if (brush) { GUI.Label(rTileId, "Brush Id(" + brushId + ")"); } else { GUI.Label(rTileId, "Id(" + tileId + ")"); } SerializedProperty randomTileDataProperty = m_randTileList.serializedProperty.GetArrayElementAtIndex(index); SerializedProperty probabilityFactorProperty = randomTileDataProperty.FindPropertyRelative("probabilityFactor"); Rect rProbabilityField = new Rect(rect.x + rTile.width + 10f, rect.y + EditorGUIUtility.singleLineHeight * 2.5f, rect.width - rTile.width - 10f, EditorGUIUtility.singleLineHeight); Rect rProbabilityLabel = new Rect(rProbabilityField.x, rProbabilityField.y - EditorGUIUtility.singleLineHeight, rProbabilityField.width, rProbabilityField.height); float sumProbabilityFactor = m_brush.GetSumProbabilityFactor(); float probability = sumProbabilityFactor >= 0 ? probabilityFactorProperty.floatValue * 100f / sumProbabilityFactor : 100f; EditorGUI.PrefixLabel(rProbabilityLabel, new GUIContent("Probability (" + Mathf.RoundToInt(probability) + "%)")); EditorGUI.PropertyField(rProbabilityField, probabilityFactorProperty, GUIContent.none); if (probabilityFactorProperty.floatValue == 0f) { serializedObject.ApplyModifiedProperties(); sumProbabilityFactor = m_brush.GetSumProbabilityFactor(); if (sumProbabilityFactor <= 0f) { probabilityFactorProperty.floatValue = 0.01f; } } if (GUI.Button(new Rect(rect.x + rect.width - 50f, rect.y, 50f, EditorGUIUtility.singleLineHeight), "Clear")) { m_brush.RandomTileList[index].tileData = Tileset.k_TileData_Empty; } }; m_randTileList.onSelectCallback += (ReorderableList list) => { TileSelectionWindow.Show(m_brush.Tileset); TileSelectionWindow.Instance.Ping(); }; m_randTileList.onAddCallback += (ReorderableList list) => { if (list.index >= 0) { list.serializedProperty.InsertArrayElementAtIndex(list.index); } else { list.serializedProperty.InsertArrayElementAtIndex(0); } list.index = Mathf.Max(0, list.index + 1); list.serializedProperty.serializedObject.ApplyModifiedProperties(); m_brush.RandomTileList[list.index].probabilityFactor = 1f; if (m_brush.Tileset.SelectedTile != null) { m_randTileList.GrabKeyboardFocus(); OnTileSelected(m_brush.Tileset, -1, m_brush.Tileset.SelectedTileId); } }; }
public static uint DoTileDataPropertiesLayout(uint tileData, Tileset tileset, bool displayBrush = true) { EditorGUILayout.BeginVertical(EditorStyles.helpBox); GUI.enabled = tileData != Tileset.k_TileData_Empty; EditorGUIUtility.labelWidth = 100; EditorGUI.BeginChangeCheck(); EditorGUILayout.Toggle("Flip Horizontally", (tileData & Tileset.k_TileFlag_FlipH) != 0); if (EditorGUI.EndChangeCheck()) { tileData ^= Tileset.k_TileFlag_FlipH; } EditorGUI.BeginChangeCheck(); EditorGUILayout.Toggle("Flip Vertically", (tileData & Tileset.k_TileFlag_FlipV) != 0); if (EditorGUI.EndChangeCheck()) { tileData ^= Tileset.k_TileFlag_FlipV; } EditorGUI.BeginChangeCheck(); EditorGUILayout.Toggle("Rotate 90º", (tileData & Tileset.k_TileFlag_Rot90) != 0); if (EditorGUI.EndChangeCheck()) { tileData ^= Tileset.k_TileFlag_Rot90; } if (displayBrush) { EditorGUI.BeginChangeCheck(); int brushId = Tileset.GetBrushIdFromTileData(tileData); TilesetBrush brush = tileset.FindBrush(brushId); brush = (TilesetBrush)EditorGUILayout.ObjectField("Brush", brush, typeof(TilesetBrush), false); if (EditorGUI.EndChangeCheck()) { if (brush && brush.Tileset != tileset) { Debug.LogWarning("The brush " + brush.name + " belongs to a different tileset and cannot be selected! "); } else { brushId = brush != null?tileset.FindBrushId(brush.name) : Tileset.k_BrushId_Default; int tileId = brush != null ? (int)(brush.PreviewTileData() & Tileset.k_TileDataMask_TileId) : Tileset.GetTileIdFromTileData(tileData); tileData &= Tileset.k_TileDataMask_Flags; tileData |= (uint)(brushId << 16) & Tileset.k_TileDataMask_BrushId; tileData |= (uint)(tileId & Tileset.k_TileDataMask_TileId); } } } if (GUILayout.Button("Reset")) { tileData = Tileset.k_TileData_Empty; } EditorGUIUtility.labelWidth = 0; GUI.enabled = true; EditorGUILayout.EndVertical(); return(tileData); }
private bool FillColliderMeshData() { //Debug.Log( "[" + ParentTilemap.name + "] FillColliderMeshData -> " + name); if (Tileset == null || ParentTilemap.ColliderType == eColliderType.None) { return(false); } System.Type collider2DType = ParentTilemap.Collider2DType == e2DColliderType.EdgeCollider2D ? typeof(EdgeCollider2D) : typeof(PolygonCollider2D); Component[] aColliders2D = null; if (ParentTilemap.ColliderType == eColliderType._3D) { int totalTiles = m_width * m_height; if (s_meshCollVertices == null) { s_meshCollVertices = new List <Vector3>(totalTiles * 4); s_meshCollTriangles = new List <int>(totalTiles * 6); } else { s_meshCollVertices.Clear(); s_meshCollTriangles.Clear(); } } else //if (ParentTilemap.ColliderType == eColliderType._2D) { m_has2DColliders = true; s_openEdges.Clear(); aColliders2D = GetComponents(collider2DType); } float halvedCollDepth = ParentTilemap.ColliderDepth / 2f; bool isEmpty = true; for (int ty = 0, tileIdx = 0; ty < m_height; ++ty) { for (int tx = 0; tx < m_width; ++tx, ++tileIdx) { uint tileData = m_tileDataList[tileIdx]; if (tileData != Tileset.k_TileData_Empty) { int tileId = (int)(tileData & Tileset.k_TileDataMask_TileId); Tile tile = Tileset.GetTile(tileId); #if ENABLE_MERGED_SUBTILE_COLLIDERS TilesetBrush brush = ParentTilemap.Tileset.FindBrush(Tileset.GetBrushIdFromTileData(tileData)); Vector2[] subTileMergedColliderVertices = brush ? brush.GetMergedSubtileColliderVertices(ParentTilemap, GridPosX + tx, GridPosY + ty, tileData) : null; #else Vector2[] subTileMergedColliderVertices = null; #endif if (tile != null) { bool hasMergedColliders = subTileMergedColliderVertices != null; TileColliderData tileCollData = tile.collData; if (tileCollData.type != eTileCollider.None || hasMergedColliders) { isEmpty = false; int neighborCollFlags = 0; // don't remove, even using neighborTileCollData, neighborTileCollData is not filled if tile is empty bool isSurroundedByFullColliders = true; for (int i = 0; i < s_neighborSegmentMinMax.Length; ++i) { s_neighborSegmentMinMax[i].x = float.MaxValue; s_neighborSegmentMinMax[i].y = float.MinValue; } System.Array.Clear(neighborTileCollData, 0, neighborTileCollData.Length); if (!hasMergedColliders) { if ((tileData & (Tileset.k_TileFlag_FlipH | Tileset.k_TileFlag_FlipV | Tileset.k_TileFlag_Rot90)) != 0) { tileCollData = tileCollData.Clone(); tileCollData.ApplyFlippingFlags(tileData); } for (int i = 0; i < 4; ++i) { uint neighborTileData; bool isTriggerOrPolygon = ParentTilemap.IsTrigger || ParentTilemap.ColliderType == eColliderType._2D && ParentTilemap.Collider2DType == e2DColliderType.PolygonCollider2D; switch (i) { case 0: // Up Tile neighborTileData = (tileIdx + m_width) < m_tileDataList.Count ? m_tileDataList[tileIdx + m_width] : isTriggerOrPolygon ? Tileset.k_TileData_Empty : ParentTilemap.GetTileData(GridPosX + tx, GridPosY + ty + 1); break; case 1: // Right Tile neighborTileData = (tileIdx + 1) % m_width != 0 ? //(tileIdx + 1) < m_tileDataList.Count ? m_tileDataList[tileIdx + 1] : isTriggerOrPolygon ? Tileset.k_TileData_Empty : ParentTilemap.GetTileData(GridPosX + tx + 1, GridPosY + ty); break; case 2: // Down Tile neighborTileData = tileIdx >= m_width ? m_tileDataList[tileIdx - m_width] : isTriggerOrPolygon ? Tileset.k_TileData_Empty : ParentTilemap.GetTileData(GridPosX + tx, GridPosY + ty - 1); break; case 3: // Left Tile neighborTileData = tileIdx % m_width != 0 ? //neighborTileId = tileIdx >= 1 ? m_tileDataList[tileIdx - 1] : isTriggerOrPolygon ? Tileset.k_TileData_Empty : ParentTilemap.GetTileData(GridPosX + tx - 1, GridPosY + ty); break; default: neighborTileData = Tileset.k_TileData_Empty; break; } int neighborTileId = (int)(neighborTileData & Tileset.k_TileDataMask_TileId); #if UNITY_EDITOR Debug.Assert(neighborTileId == Tileset.k_TileId_Empty || neighborTileId < Tileset.Tiles.Count, "Wrong neighbor tileId " + neighborTileId + " not found in the tileset!"); #endif if (neighborTileId != Tileset.k_TileId_Empty && neighborTileId < Tileset.Tiles.Count) { Vector2 segmentMinMax; TileColliderData neighborTileCollider; neighborTileCollider = Tileset.Tiles[neighborTileId].collData; if ((neighborTileData & (Tileset.k_TileFlag_FlipH | Tileset.k_TileFlag_FlipV | Tileset.k_TileFlag_Rot90)) != 0) { neighborTileCollider = neighborTileCollider.Clone(); if ((neighborTileData & Tileset.k_TileFlag_FlipH) != 0) { neighborTileCollider.FlipH(); } if ((neighborTileData & Tileset.k_TileFlag_FlipV) != 0) { neighborTileCollider.FlipV(); } if ((neighborTileData & Tileset.k_TileFlag_Rot90) != 0) { neighborTileCollider.Rot90(); } } neighborTileCollData[i] = neighborTileCollider; isSurroundedByFullColliders &= (neighborTileCollider.type == eTileCollider.Full); if (neighborTileCollider.type == eTileCollider.None) { segmentMinMax = new Vector2(float.MaxValue, float.MinValue); //NOTE: x will be min, y will be max } else if (neighborTileCollider.type == eTileCollider.Full) { segmentMinMax = new Vector2(0f, 1f); //NOTE: x will be min, y will be max neighborCollFlags |= (1 << i); } else { segmentMinMax = new Vector2(float.MaxValue, float.MinValue); //NOTE: x will be min, y will be max neighborCollFlags |= (1 << i); for (int j = 0; j < neighborTileCollider.vertices.Length; ++j) { Vector2 v = neighborTileCollider.vertices[j]; { if (i == 0 && v.y == 0 || i == 2 && v.y == 1) //Top || Bottom { if (v.x < segmentMinMax.x) { segmentMinMax.x = v.x; } if (v.x > segmentMinMax.y) { segmentMinMax.y = v.x; } } else if (i == 1 && v.x == 0 || i == 3 && v.x == 1) //Right || Left { if (v.y < segmentMinMax.x) { segmentMinMax.x = v.y; } if (v.y > segmentMinMax.y) { segmentMinMax.y = v.y; } } } } } s_neighborSegmentMinMax[i] = segmentMinMax; } else { isSurroundedByFullColliders = false; } } } // Create Mesh Colliders if (isSurroundedByFullColliders && !hasMergedColliders) { //Debug.Log(" Surrounded! " + tileIdx); } else { float px0 = tx * CellSize.x; float py0 = ty * CellSize.y; Vector2[] collVertices = subTileMergedColliderVertices; if (!hasMergedColliders) { collVertices = tileCollData.type == eTileCollider.Full ? s_fullCollTileVertices : tileCollData.vertices; } for (int i = 0; i < collVertices.Length; ++i) { Vector2 s0 = collVertices[i]; Vector2 s1 = collVertices[i == (collVertices.Length - 1) ? 0 : i + 1]; if (hasMergedColliders) { ++i; // add ++i; in this case to go 2 by 2 because the collVertices for merged colliders will have the segments in pairs } // full collider optimization if ((tileCollData.type == eTileCollider.Full) && ( (i == 0 && neighborTileCollData[3].type == eTileCollider.Full) || // left tile has collider (i == 1 && neighborTileCollData[0].type == eTileCollider.Full) || // top tile has collider (i == 2 && neighborTileCollData[1].type == eTileCollider.Full) || // right tile has collider (i == 3 && neighborTileCollData[2].type == eTileCollider.Full) // bottom tile has collider ) ) { continue; } // polygon collider optimization else // if( tileCollData.type == eTileCollider.Polygon ) Or Full colliders if neighbor is not Full as well { Vector2 n, m; if (s0.y == 1f && s1.y == 1f) // top side { if ((neighborCollFlags & 0x1) != 0) // top tile has collider { n = s_neighborSegmentMinMax[0]; if (n.x < n.y && n.x <= s0.x && n.y >= s1.x) { continue; } } } else if (s0.x == 1f && s1.x == 1f) // right side { if ((neighborCollFlags & 0x2) != 0) // right tile has collider { n = s_neighborSegmentMinMax[1]; if (n.x < n.y && n.x <= s1.y && n.y >= s0.y) { continue; } } } else if (s0.y == 0f && s1.y == 0f) // bottom side { if ((neighborCollFlags & 0x4) != 0) // bottom tile has collider { n = s_neighborSegmentMinMax[2]; if (n.x < n.y && n.x <= s1.x && n.y >= s0.x) { continue; } } } else if (s0.x == 0f && s1.x == 0f) // left side { if ((neighborCollFlags & 0x8) != 0) // left tile has collider { n = s_neighborSegmentMinMax[3]; if (n.x < n.y && n.x <= s0.y && n.y >= s1.y) { continue; } } } else if (s0.y == 1f && s1.x == 1f) // top - right diagonal { if ((neighborCollFlags & 0x1) != 0 && (neighborCollFlags & 0x2) != 0) { n = s_neighborSegmentMinMax[0]; m = s_neighborSegmentMinMax[1]; if ((n.x < n.y && n.x <= s0.x && n.y == 1f) && (m.x < m.y && m.x <= s1.y && m.y == 1f)) { continue; } } } else if (s0.x == 1f && s1.y == 0f) // right - bottom diagonal { if ((neighborCollFlags & 0x2) != 0 && (neighborCollFlags & 0x4) != 0) { n = s_neighborSegmentMinMax[1]; m = s_neighborSegmentMinMax[2]; if ((n.x < n.y && n.x == 0f && n.y >= s0.y) && (m.x < m.y && m.x <= s1.x && m.y == 1f)) { continue; } } } else if (s0.y == 0f && s1.x == 0f) // bottom - left diagonal { if ((neighborCollFlags & 0x4) != 0 && (neighborCollFlags & 0x8) != 0) { n = s_neighborSegmentMinMax[2]; m = s_neighborSegmentMinMax[3]; if ((n.x < n.y && n.x == 0f && n.y >= s0.x) && (m.x < m.y && m.x == 0f && m.y >= s1.y)) { continue; } } } else if (s0.x == 0f && s1.y == 1f) // left - top diagonal { if ((neighborCollFlags & 0x8) != 0 && (neighborCollFlags & 0x1) != 0) { n = s_neighborSegmentMinMax[3]; m = s_neighborSegmentMinMax[0]; if ((n.x < n.y && n.x <= s0.y && n.y == 1f) && (m.x < m.y && m.x == 0f && m.y >= s1.x)) { continue; } } } } // Update s0 and s1 to world positions s0.x = px0 + CellSize.x * s0.x; s0.y = py0 + CellSize.y * s0.y; s1.x = px0 + CellSize.x * s1.x; s1.y = py0 + CellSize.y * s1.y; if (ParentTilemap.ColliderType == eColliderType._3D) { int collVertexIdx = s_meshCollVertices.Count; s_meshCollVertices.Add(new Vector3(s0.x, s0.y, -halvedCollDepth)); s_meshCollVertices.Add(new Vector3(s0.x, s0.y, halvedCollDepth)); s_meshCollVertices.Add(new Vector3(s1.x, s1.y, halvedCollDepth)); s_meshCollVertices.Add(new Vector3(s1.x, s1.y, -halvedCollDepth)); s_meshCollTriangles.Add(collVertexIdx + 0); s_meshCollTriangles.Add(collVertexIdx + 1); s_meshCollTriangles.Add(collVertexIdx + 2); s_meshCollTriangles.Add(collVertexIdx + 2); s_meshCollTriangles.Add(collVertexIdx + 3); s_meshCollTriangles.Add(collVertexIdx + 0); } else //if( ParentTilemap.ColliderType == eColliderType._2D ) { int linkedSegments = 0; int segmentIdxToMerge = -1; for (int edgeIdx = s_openEdges.Count - 1; edgeIdx >= 0 && linkedSegments < 2; --edgeIdx) { LinkedList <Vector2> edgeSegments = s_openEdges[edgeIdx]; if (edgeSegments.First.Value == edgeSegments.Last.Value) { continue; //skip closed edges } if (edgeSegments.Last.Value == s0) { if (segmentIdxToMerge >= 0) { LinkedList <Vector2> segmentToMerge = s_openEdges[segmentIdxToMerge]; if (s0 == segmentToMerge.First.Value) { for (LinkedListNode <Vector2> node = segmentToMerge.First.Next; node != null; node = node.Next) { edgeSegments.AddLast(node.Value); } s_openEdges.RemoveAt(segmentIdxToMerge); } /* Cannot join head with head or tail with tail, it will change the segment normal * else * for (LinkedListNode<Vector2> node = segmentToMerge.Last.Previous; node != null; node = node.Previous) * edgeSegments.AddLast(node.Value);*/ } else { segmentIdxToMerge = edgeIdx; edgeSegments.AddLast(s1); } ++linkedSegments; } /* Cannot join head with head or tail with tail, it will change the segment normal * else if( edgeSegments.Last.Value == s1 ) * else if (edgeSegments.First.Value == s0)*/ else if (edgeSegments.First.Value == s1) { if (segmentIdxToMerge >= 0) { LinkedList <Vector2> segmentToMerge = s_openEdges[segmentIdxToMerge]; if (s1 == segmentToMerge.Last.Value) { for (LinkedListNode <Vector2> node = edgeSegments.First.Next; node != null; node = node.Next) { segmentToMerge.AddLast(node.Value); } s_openEdges.RemoveAt(edgeIdx); } /* Cannot join head with head or tail with tail, it will change the segment normal * else * for (LinkedListNode<Vector2> node = edgeSegments.First.Next; node != null; node = node.Next) * segmentToMerge.AddFirst(node.Value);*/ } else { segmentIdxToMerge = edgeIdx; edgeSegments.AddFirst(s0); } ++linkedSegments; } } if (linkedSegments == 0) { LinkedList <Vector2> newEdge = new LinkedList <Vector2>(); newEdge.AddFirst(s0); newEdge.AddLast(s1); s_openEdges.Add(newEdge); } } } } } } } } } if (ParentTilemap.ColliderType == eColliderType._2D) { //+++ Process Edges //(NOTE: this was added to fix issues related with lighting, otherwise leave this commented) { // Remove vertex inside a line RemoveRedundantVertices(s_openEdges); // Split segments (NOTE: This is not working with polygon colliders) /*/ commented unless necessary for performance reasons * if (ParentTilemap.Collider2DType == e2DColliderType.EdgeCollider2D) * { * openEdges = SplitSegments(openEdges); * } * //*/ } //--- //Create Edges for (int i = 0; i < s_openEdges.Count; ++i) { LinkedList <Vector2> edgeSegments = s_openEdges[i]; //skip invalid segments if (edgeSegments == null || edgeSegments.Count < 2) { continue; } bool reuseCollider = i < aColliders2D.Length; Collider2D collider2D = reuseCollider ? (Collider2D)aColliders2D[i] : (Collider2D)gameObject.AddComponent(collider2DType); collider2D.enabled = true; collider2D.isTrigger = ParentTilemap.IsTrigger; collider2D.sharedMaterial = ParentTilemap.PhysicMaterial2D; if (ParentTilemap.Collider2DType == e2DColliderType.EdgeCollider2D) { ((EdgeCollider2D)collider2D).points = edgeSegments.ToArray(); } else { ((PolygonCollider2D)collider2D).SetPath(0, edgeSegments.ToArray()); } } //Destroy unused edge colliders for (int i = s_openEdges.Count; i < aColliders2D.Length; ++i) { if (!s_isOnValidate) { DestroyImmediate(aColliders2D[i]); } else { ((Collider2D)aColliders2D[i]).enabled = false; } } } return(!isEmpty); }
public override void OnInspectorGUI() { serializedObject.Update(); if (m_prevTileset != m_brush.Tileset) { if (m_prevTileset) { m_prevTileset.OnBrushSelected -= OnBrushSelected; m_prevTileset.OnTileSelected -= OnTileSelected; } OnDisable(); OnEnable(); } m_prevTileset = m_brush.Tileset; base.OnInspectorGUI(); if (!m_brush.Tileset) { return; } Vector2 visualTileSize = m_brush.Tileset.VisualTileSize; EditorGUILayout.Space(); GUILayoutUtility.GetRect(1f, 1f, GUILayout.Width(visualTileSize.x), GUILayout.Height(visualTileSize.y)); Rect rSelectedTile = GUILayoutUtility.GetLastRect(); uint tileData = m_brush.GetAnimTileData(); if (tileData != Tileset.k_TileData_Empty) { rSelectedTile.center = new Vector2(EditorGUIUtility.currentViewWidth / 2, rSelectedTile.center.y); GUI.Box(new Rect(rSelectedTile.position - Vector2.one, rSelectedTile.size + 2 * Vector2.one), ""); TilesetEditor.DoGUIDrawTileFromTileData(rSelectedTile, tileData, m_brush.Tileset); } EditorGUILayout.Space(); SerializedProperty randomFlagMaskProperty = serializedObject.FindProperty("RandomizeFlagMask"); System.Enum enumNew = EditorCompatibilityUtils.EnumMaskField(new GUIContent("Random Flags", "Applies random flags when painting tiles"), (eRandomFlags)(randomFlagMaskProperty.longValue >> 29)); randomFlagMaskProperty.longValue = ((long)System.Convert.ChangeType(enumNew, typeof(long)) & 0x7) << 29; uint brushTileData = m_randTileList.index >= 0 ? m_brush.RandomTileList[m_randTileList.index].tileData : Tileset.k_TileData_Empty; brushTileData = BrushTileGridControl.DoTileDataPropertiesLayout(brushTileData, m_brush.Tileset, false); if (m_randTileList.index >= 0) { m_brush.RandomTileList[m_randTileList.index].tileData = brushTileData; } EditorGUILayout.Space(); EditorGUILayout.HelpBox("Activate this to use animated brushes as random tiles", MessageType.Info); EditorGUILayout.PropertyField(serializedObject.FindProperty("RemoveBrushIdAfterRefresh")); // Draw List m_randTileList.elementHeight = visualTileSize.y + 35f; m_randTileList.DoLayoutList(); if (Event.current.type == EventType.Repaint) { m_randTileListHasFocus = GUIUtility.keyboardControl == randTileListControlId; } TileSelection tileSelection = ((TilesetBrush)target).Tileset.TileSelection; if (tileSelection != null) { if (GUILayout.Button("Add tiles from tile selection")) { m_brush.RandomTileList.AddRange(tileSelection.selectionData.Select(x => new RandomBrush.RandomTileData() { tileData = x, probabilityFactor = 1f })); } } EditorGUILayout.HelpBox("Select a tile from list and then select a tile from tile selection window.", MessageType.Info); EditorGUILayout.HelpBox("Add and Remove tiles with '+' and '-' buttons.", MessageType.Info); Repaint(); serializedObject.ApplyModifiedProperties(); if (GUI.changed) { m_brush.InvalidateSortedList(); EditorUtility.SetDirty(target); } }
//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; } } } } } } } }
//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"); }
public override void OnInspectorGUI() { Tileset tileset = (Tileset)target; serializedObject.Update(); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(serializedObject.FindProperty("AtlasTexture")); if (EditorGUI.EndChangeCheck()) { serializedObject.ApplyModifiedProperties(); tileset.UpdateTilesetConfigFromAtlasImportSettings(); } if (tileset.AtlasTexture == null) { EditorGUILayout.HelpBox("Select an atlas texture for the tileset", MessageType.Info); } else { EditorGUILayout.PropertyField(serializedObject.FindProperty("m_pixelsPerUnit")); s_atlasSettingsFoldout = EditorGUILayout.Foldout(s_atlasSettingsFoldout, "Atlas Settings"); if (s_atlasSettingsFoldout) { EditorGUILayout.BeginVertical(EditorStyles.helpBox); tileset.TilePxSize = _GetPositiveIntVect2(EditorGUILayout.Vector2Field("Tile Size (pixels)", tileset.TilePxSize)); tileset.SliceOffset = _GetPositiveIntVect2(EditorGUILayout.Vector2Field(new GUIContent("Offset", "The offset position in pixels to start slicing tiles from the atlas texture"), tileset.SliceOffset)); tileset.SlicePadding = _GetPositiveIntVect2(EditorGUILayout.Vector2Field(new GUIContent("Padding", "The separation in pixels between tiles"), tileset.SlicePadding)); if (GUILayout.Button("Slice Atlas")) { tileset.Slice(); } EditorGUILayout.EndVertical(); } EditorGUILayout.Separator(); if (GUILayout.Button("Import TMX into the Scene")) { CreativeSpore.TiledImporter.TmxImporter.ImportTmxIntoTheScene(tileset); } EditorGUILayout.Separator(); string[] modeNames = System.Enum.GetNames(typeof(eMode)); s_mode = (eMode)GUILayout.Toolbar((int)s_mode, modeNames); switch (s_mode) { case eMode.Tiles: m_tilesetCtrl.Tileset = tileset; m_tilesetCtrl.Display(); Repaint(); break; case eMode.BrushGroups: s_brushGroupsFoldout = EditorGUILayout.Foldout(s_brushGroupsFoldout, "Groups"); if (s_brushGroupsFoldout) { m_groupsList.DoLayoutList(); } GroupMatrixGUI.DoGUI("Group Autotiling Mask", tileset.BrushGroupNames, ref s_brushAutotilingMaskFoldout, ref s_brushGroupMatrixScrollPos, GetValue, SetValue); EditorGUILayout.HelpBox("Check the group that should autotile between them when Autotiling Mode Group is enabled in a brush", MessageType.Info); break; } } if (GUI.changed) { serializedObject.ApplyModifiedProperties(); EditorUtility.SetDirty(target); } }
void OnGUI() { bool sliceTileset = false; m_scrollPos = EditorGUILayout.BeginScrollView(m_scrollPos, GUIStyle.none, GUI.skin.verticalScrollbar); { EditorGUILayout.Space(); EditorGUILayout.BeginVertical(EditorStyles.helpBox); { EditorGUILayout.LabelField("Atlas Texture:", EditorStyles.boldLabel); EditorGUI.indentLevel += 1; EditorGUI.BeginChangeCheck(); m_tileset = (Tileset)EditorGUILayout.ObjectField("Tileset (optional)", m_tileset, typeof(Tileset), false); if (EditorGUI.EndChangeCheck() && m_tileset) { m_padding = (int)Mathf.Max(m_slicePadding.x, m_slicePadding.y); m_extrude = 0; } // Read Data From Tileset if (m_tileset) { m_tileSize = m_tileset.TilePxSize; m_slicePadding = m_tileset.SlicePadding; m_sliceOffset = m_tileset.SliceOffset; m_atlasTexture = m_tileset.AtlasTexture; } m_atlasTexture = (Texture2D)EditorGUILayout.ObjectField("Atlas texture", m_atlasTexture, typeof(Texture2D), false); EditorGUI.indentLevel -= 1; } EditorGUILayout.EndHorizontal(); GUI.enabled = m_atlasTexture != null; EditorGUILayout.Space(); EditorGUILayout.BeginVertical(EditorStyles.helpBox); { EditorGUILayout.LabelField("Slice Settings:", EditorStyles.boldLabel); EditorGUI.indentLevel += 1; EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Tile Size (pixels)", GUILayout.MaxWidth(120f)); m_tileSize = EditorGUILayout.Vector2Field("", m_tileSize, GUILayout.MaxWidth(180f), GUILayout.MaxHeight(1f)); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Offset", GUILayout.MaxWidth(120f)); m_sliceOffset = EditorGUILayout.Vector2Field("", m_sliceOffset, GUILayout.MaxWidth(180f), GUILayout.MaxHeight(1f)); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Padding", GUILayout.MaxWidth(120f)); m_slicePadding = EditorGUILayout.Vector2Field("", m_slicePadding, GUILayout.MaxWidth(180f), GUILayout.MaxHeight(1f)); EditorGUILayout.EndHorizontal(); EditorGUI.indentLevel -= 1; } EditorGUILayout.EndVertical(); EditorGUILayout.Space(); EditorGUILayout.BeginVertical(EditorStyles.helpBox); { EditorGUILayout.LabelField("New Settings:", EditorStyles.boldLabel); EditorGUI.indentLevel += 1; m_padding = EditorGUILayout.IntField(new GUIContent("Padding (pixels)", "Separation between tiles in pixels"), m_padding); m_extrude = EditorGUILayout.IntField(new GUIContent("Extrude (pixels)", "How many pixels the color is extruded from tile border"), m_extrude); m_padding = Mathf.Max(0, m_padding, m_extrude * 2); m_extrude = Mathf.Max(0, m_extrude); if (GUILayout.Button("Preview")) { m_previewTexture = BuildAtlas(m_atlasTexture, m_padding, m_extrude, m_tileSize, m_sliceOffset, m_slicePadding); AtlasPreviewWindow atlasPreviewWnd = EditorWindow.GetWindow <AtlasPreviewWindow>(true, "Atlas Preview", true); atlasPreviewWnd.Texture = m_previewTexture; atlasPreviewWnd.TileSize = m_tileSize; atlasPreviewWnd.Padding = m_padding; atlasPreviewWnd.Extrude = m_extrude; atlasPreviewWnd.ShowUtility(); } if (GUILayout.Button("Apply Settings")) { Texture2D outputAtlas = BuildAtlas(m_atlasTexture, m_padding, m_extrude, m_tileSize, m_sliceOffset, m_slicePadding); byte[] pngData = outputAtlas.EncodeToPNG(); string atlasTexturePath = Application.dataPath + AssetDatabase.GetAssetPath(m_atlasTexture).Substring(6); System.IO.File.WriteAllBytes(atlasTexturePath, pngData); AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(m_atlasTexture)); Debug.Log("Saving atlas texture: " + atlasTexturePath); if (m_tileset) { m_sliceOffset = new Vector2(m_padding, m_padding); m_slicePadding = m_sliceOffset; sliceTileset = true; } } EditorGUI.indentLevel -= 1; } EditorGUILayout.EndVertical(); if (m_previewTexture) { GUILayout.Box(m_previewTexture, GUILayout.Width(position.width - 24f)); } GUI.enabled = true; } EditorGUILayout.EndScrollView(); // Save Data into tileset if (m_tileset) { m_tileset.TilePxSize = m_tileSize; m_tileset.SlicePadding = m_slicePadding; m_tileset.SliceOffset = m_sliceOffset; m_tileset.AtlasTexture = m_atlasTexture; if (sliceTileset) { m_tileset.Slice(); foreach (Tilemap tilemap in FindObjectsOfType <Tilemap>()) { if (tilemap.Tileset == m_tileset) { tilemap.Refresh(true, false); } } } } if (GUI.changed) { if (m_tileset) { EditorUtility.SetDirty(m_tileset); } } }
public static ReorderableList CreateTileViewReorderableList(Tileset tileset) { ReorderableList tileViewRList = new ReorderableList(tileset.TileViews, typeof(TileView), true, true, true, true); tileViewRList.onAddDropdownCallback = (Rect buttonRect, ReorderableList l) => { GenericMenu menu = new GenericMenu(); GenericMenu.MenuFunction addTileSelectionFunc = () => { TileSelection tileSelection = tileset.TileSelection.Clone(); tileSelection.FlipVertical(); // flip vertical to fit the tileset coordinate system ( from top to bottom ) tileset.AddTileView("new TileView", tileSelection); EditorUtility.SetDirty(tileset); }; GenericMenu.MenuFunction addBrushSelectionFunc = () => { TileSelection tileSelection = BrushBehaviour.CreateTileSelection(); tileset.AddTileView("new TileView", tileSelection); EditorUtility.SetDirty(tileset); }; GenericMenu.MenuFunction removeAllTileViewsFunc = () => { if (EditorUtility.DisplayDialog("Warning!", "Are you sure you want to delete all the TileViews?", "Yes", "No")) { tileset.RemoveAllTileViews(); EditorUtility.SetDirty(tileset); } }; if (tileset.TileSelection != null) { menu.AddItem(new GUIContent("Add Tile Selection"), false, addTileSelectionFunc); } else { menu.AddDisabledItem(new GUIContent("Add Tile Selection to TileView")); } if (BrushBehaviour.GetBrushTileset() == tileset && BrushBehaviour.CreateTileSelection() != null) { menu.AddItem(new GUIContent("Add Brush Selection"), false, addBrushSelectionFunc); } menu.AddSeparator(""); menu.AddItem(new GUIContent("Remove All TileViews"), false, removeAllTileViewsFunc); menu.AddSeparator(""); menu.AddItem(new GUIContent("Sort By Name"), false, tileset.SortTileViewsByName); menu.ShowAsContext(); }; tileViewRList.onRemoveCallback = (ReorderableList list) => { if (EditorUtility.DisplayDialog("Warning!", "Are you sure you want to delete the TileView?", "Yes", "No")) { ReorderableList.defaultBehaviours.DoRemoveButton(list); EditorUtility.SetDirty(tileset); } }; tileViewRList.drawHeaderCallback = (Rect rect) => { EditorGUI.LabelField(rect, "TileViews", EditorStyles.boldLabel); Texture2D btnTexture = tileViewRList.elementHeight == 0f ? EditorGUIUtility.FindTexture("winbtn_win_max_h") : EditorGUIUtility.FindTexture("winbtn_win_min_h"); if (GUI.Button(new Rect(rect.width - rect.height, rect.y, rect.height, rect.height), btnTexture, EditorStyles.label)) { tileViewRList.elementHeight = tileViewRList.elementHeight == 0f ? EditorGUIUtility.singleLineHeight : 0f; tileViewRList.draggable = tileViewRList.elementHeight > 0f; } }; tileViewRList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => { if (tileViewRList.elementHeight == 0f) { return; } Rect rLabel = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight); TileView tileView = tileViewRList.list[index] as TileView; if (index == tileViewRList.index) { string newName = EditorGUI.TextField(rLabel, tileView.name); if (newName != tileView.name) { tileset.RenameTileView(tileView.name, newName); } } else { EditorGUI.LabelField(rLabel, tileView.name); } }; return(tileViewRList); }
private void SetValue(int groupA, int groupB, bool val) { Tileset tileset = (Tileset)target; tileset.SetGroupAutotiling(groupA, groupB, val); }
private bool GetValue(int groupA, int groupB) { Tileset tileset = (Tileset)target; return(tileset.GetGroupAutotiling(groupA, groupB)); }
public override void OnInspectorGUI() { serializedObject.Update(); if (m_prevTileset != m_brush.Tileset) { OnDisable(); OnEnable(); } m_prevTileset = m_brush.Tileset; base.OnInspectorGUI(); if (!m_brush.Tileset) { return; } Vector2 visualTileSize = m_brush.Tileset.VisualTileSize; EditorGUILayout.PropertyField(serializedObject.FindProperty("AnimFPS")); TileSelection tileSelection = ((TilesetBrush)target).Tileset.TileSelection; if (tileSelection != null) { if (GUILayout.Button("Add tile selection as animation frames")) { ((AnimBrush)target).AnimFrames.AddRange(tileSelection.selectionData.Select(x => new AnimBrush.TileAnimFrame() { tileId = x })); } } EditorGUILayout.Space(); // Draw animation GUILayoutUtility.GetRect(1f, 1f, GUILayout.Width(visualTileSize.x), GUILayout.Height(visualTileSize.y)); Rect rAnimFrame = GUILayoutUtility.GetLastRect(); uint tileData = m_brush.GetAnimTileData(); rAnimFrame.center = new Vector2(EditorGUIUtility.currentViewWidth / 2, rAnimFrame.center.y); GUI.Box(new Rect(rAnimFrame.position - Vector2.one, rAnimFrame.size + 2 * Vector2.one), ""); TilesetEditor.DoGUIDrawTileFromTileData(rAnimFrame, tileData, m_brush.Tileset, m_brush.GetAnimUV()); EditorGUILayout.Space(); uint brushTileData = m_frameList.index >= 0 ? m_brush.AnimFrames[m_frameList.index].tileId : Tileset.k_TileData_Empty; brushTileData = BrushTileGridControl.DoTileDataPropertiesLayout(brushTileData, m_brush.Tileset, false); if (m_frameList.index >= 0) { m_brush.AnimFrames[m_frameList.index].tileId = brushTileData; } EditorGUILayout.Space(); // Draw Frames List m_frameList.elementHeight = visualTileSize.y + 10f; m_frameList.DoLayoutList(); EditorGUILayout.HelpBox("Select a frame from list and then select a tile from tile selection window.", MessageType.Info); EditorGUILayout.HelpBox("Add and Remove tiles with '+' and '-' buttons.", MessageType.Info); Repaint(); serializedObject.ApplyModifiedProperties(); if (GUI.changed) { EditorUtility.SetDirty(target); } }
/// <summary> /// Fill the mesh data and return false if all tiles are empty /// </summary> /// <returns></returns> private bool FillMeshData() { //Debug.Log( "[" + ParentTilemap.name + "] FillData -> " + name); if (!Tileset || !Tileset.AtlasTexture) { return(false); } s_currUpdatedTilechunk = this; int totalTiles = m_width * m_height; if (s_vertices == null) { s_vertices = new List <Vector3>(totalTiles * 4); } else { s_vertices.Clear(); } if (s_triangles == null) { s_triangles = new List <int>(totalTiles * 6); } else { s_triangles.Clear(); } if (s_colors32 == null) { s_colors32 = new List <Color32>(totalTiles * 4); } else { s_colors32.Clear(); } if (m_uv == null) { m_uv = new List <Vector2>(totalTiles * 4); } else { m_uv.Clear(); } Vector2[] subTileOffset = new Vector2[] { new Vector2(0f, 0f), new Vector2(CellSize.x / 2f, 0f), new Vector2(0f, CellSize.y / 2f), new Vector2(CellSize.x / 2f, CellSize.y / 2f), }; Vector2 subTileSize = CellSize / 2f; m_animatedTiles.Clear(); bool isEmpty = true; for (int ty = 0, tileIdx = 0; ty < m_height; ++ty) { for (int tx = 0; tx < m_width; ++tx, ++tileIdx) { uint tileData = m_tileDataList[tileIdx]; if (tileData != Tileset.k_TileData_Empty) { int brushId = (int)((tileData & Tileset.k_TileDataMask_BrushId) >> 16); int tileId = (int)(tileData & Tileset.k_TileDataMask_TileId); Tile tile = Tileset.GetTile(tileId); TilesetBrush tileBrush = null; if (brushId > 0) { tileBrush = Tileset.FindBrush(brushId); if (tileBrush == null) { Debug.LogWarning(ParentTilemap.name + "\\" + name + ": BrushId " + brushId + " not found! GridPos(" + tx + "," + ty + ") tilaData 0x" + tileData.ToString("X")); m_tileDataList[tileIdx] = tileData & ~Tileset.k_TileDataMask_BrushId; } if (tileBrush != null && (m_invalidateBrushes || (tileData & Tileset.k_TileFlag_Updated) == 0)) { tileData = tileBrush.Refresh(ParentTilemap, GridPosX + tx, GridPosY + ty, tileData); //+++NOTE: this code add support for animated brushes inside a random brush // Collateral effects of supporting changing the brush id in Refresh: // - When the random brush select a tile data with another brush id, this tile won't be a random tile any more // - If the tilemap is refreshed several times, and at least a tile data contains another brush id, then all tiles will loose the brush id of the random brush if (BrushBehaviour.Instance.BrushTilemap == ParentTilemap) // avoid changing brushId when updating the BrushTilemap { tileData &= ~Tileset.k_TileDataMask_BrushId; tileData |= (uint)(brushId << 16); } int newBrushId = (int)((tileData & Tileset.k_TileDataMask_BrushId) >> 16); if (brushId != newBrushId) { brushId = newBrushId; tileBrush = Tileset.FindBrush(brushId); } //--- tileData |= Tileset.k_TileFlag_Updated; // set updated flag m_tileDataList[tileIdx] = tileData; // update tileData tileId = (int)(tileData & Tileset.k_TileDataMask_TileId); tile = Tileset.GetTile(tileId); // update created objects if (tile != null && tile.prefabData.prefab != null) { CreateTileObject(tileIdx, tile.prefabData); } else { DestroyTileObject(tileIdx); } } } isEmpty = false; if (tileBrush != null && tileBrush.IsAnimated()) { m_animatedTiles.Add(new AnimTileData() { VertexIdx = s_vertices.Count, Brush = tileBrush, SubTileIdx = -1 }); } s_currUVVertex = s_vertices.Count; Rect tileUV; uint[] subtileData = tileBrush != null?tileBrush.GetSubtiles(ParentTilemap, GridPosX + tx, GridPosY + ty, tileData) : null; if (subtileData == null) { if (tile != null) { if (tile.prefabData.prefab == null || tile.prefabData.showTileWithPrefab || //hide the tiles with prefabs ( unless showTileWithPrefab is true ) tileBrush && tileBrush.IsAnimated()) // ( skip if it's an animated brush ) { tileUV = tile.uv; _AddTileToMesh(tileUV, tx, ty, tileData, Vector2.zero, CellSize); if (m_tileColorList != null && m_tileColorList.Count > tileIdx) { TileColor32 tileColor32 = m_tileColorList[tileIdx]; s_colors32.Add(tileColor32.c0); s_colors32.Add(tileColor32.c1); s_colors32.Add(tileColor32.c2); s_colors32.Add(tileColor32.c3); } } } } else { for (int i = 0; i < subtileData.Length; ++i) { uint subTileData = subtileData[i]; int subTileId = (int)(subTileData & Tileset.k_TileDataMask_TileId); Tile subTile = Tileset.GetTile(subTileId); tileUV = subTile != null ? subTile.uv : default(Rect); //if (tileUV != default(Rect)) //NOTE: if this is uncommented, there won't be coherence with geometry ( 16 vertices per tiles with subtiles ). But it means also, the tile shouldn't be null. { _AddTileToMesh(tileUV, tx, ty, subTileData, subTileOffset[i], subTileSize, i); if (m_tileColorList != null && m_tileColorList.Count > tileIdx) { TileColor32 tileColor32 = m_tileColorList[tileIdx]; Color32 middleColor = new Color32( System.Convert.ToByte((tileColor32.c0.r + tileColor32.c1.r + tileColor32.c2.r + tileColor32.c3.r) >> 2), System.Convert.ToByte((tileColor32.c0.g + tileColor32.c1.g + tileColor32.c2.g + tileColor32.c3.g) >> 2), System.Convert.ToByte((tileColor32.c0.b + tileColor32.c1.b + tileColor32.c2.b + tileColor32.c3.b) >> 2), System.Convert.ToByte((tileColor32.c0.a + tileColor32.c1.a + tileColor32.c2.a + tileColor32.c3.a) >> 2) ); switch (i) { case 0: s_colors32.Add(tileColor32.c0); s_colors32.Add(Color32.Lerp(tileColor32.c1, tileColor32.c0, .5f)); s_colors32.Add(Color32.Lerp(tileColor32.c2, tileColor32.c0, .5f)); s_colors32.Add(middleColor); break; case 1: s_colors32.Add(Color32.Lerp(tileColor32.c0, tileColor32.c1, .5f)); s_colors32.Add(tileColor32.c1); s_colors32.Add(middleColor); s_colors32.Add(Color32.Lerp(tileColor32.c3, tileColor32.c1, .5f)); break; case 2: s_colors32.Add(Color32.Lerp(tileColor32.c0, tileColor32.c2, .5f)); s_colors32.Add(middleColor); s_colors32.Add(tileColor32.c2); s_colors32.Add(Color32.Lerp(tileColor32.c3, tileColor32.c2, .5f)); break; case 3: s_colors32.Add(middleColor); s_colors32.Add(Color32.Lerp(tileColor32.c1, tileColor32.c3, .5f)); s_colors32.Add(Color32.Lerp(tileColor32.c2, tileColor32.c3, .5f)); s_colors32.Add(tileColor32.c3); break; } } } } } } } } //NOTE: the destruction of tileobjects needs to be done here to avoid a Undo/Redo bug. Check inside DestroyTileObject for more information. for (int i = 0; i < m_tileObjToBeRemoved.Count; ++i) { DestroyTileObject(m_tileObjToBeRemoved[i]); } m_tileObjToBeRemoved.Clear(); s_currUpdatedTilechunk = null; return(!isEmpty); }