Example #1
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   = 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);
                }
            }
        }
Example #2
0
 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);
            }
        }
Example #7
0
        //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;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Example #8
0
        //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");
        }
Example #9
0
        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);
                }
            }
        }
Example #11
0
        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);
        }
Example #12
0
        private void SetValue(int groupA, int groupB, bool val)
        {
            Tileset tileset = (Tileset)target;

            tileset.SetGroupAutotiling(groupA, groupB, val);
        }
Example #13
0
        private bool GetValue(int groupA, int groupB)
        {
            Tileset tileset = (Tileset)target;

            return(tileset.GetGroupAutotiling(groupA, groupB));
        }
Example #14
0
        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);
        }