예제 #1
0
        /// <summary>
        /// Get the parameter container from tileData if tileData contains a tile with parameters or Null in other case
        /// </summary>
        static public ParameterContainer GetParamsFromTileData(Tileset tileset, uint tileData)
        {
            int          brushId = Tileset.GetBrushIdFromTileData(tileData);
            TilesetBrush brush   = tileset.FindBrush(brushId);

            if (brush)
            {
                return(brush.Params);
            }
            else
            {
                int  tileId = Tileset.GetTileIdFromTileData(tileData);
                Tile tile   = tileset.GetTile(tileId);
                if (tile != null)
                {
                    return(tile.paramContainer);
                }
            }
            return(null);
        }
예제 #2
0
 public static void DoGUIDrawTileFromTileData(Rect dstRect, uint tileData, Tileset tileset, Rect customUV = default(Rect))
 {
     if (Event.current.type == EventType.Repaint)
     {
         int  tileId = (int)(tileData & Tileset.k_TileDataMask_TileId);
         Tile tile   = tileset.GetTile(tileId);
         if (tileId != Tileset.k_TileId_Empty && tileset.AtlasTexture)
         {
             if ((tileData & Tileset.k_TileFlag_FlipV) != 0)
             {
                 GUIUtility.ScaleAroundPivot(new Vector2(1f, -1f), dstRect.center);
             }
             if ((tileData & Tileset.k_TileFlag_FlipH) != 0)
             {
                 GUIUtility.ScaleAroundPivot(new Vector2(-1f, 1f), dstRect.center);
             }
             if ((tileData & Tileset.k_TileFlag_Rot90) != 0)
             {
                 GUIUtility.RotateAroundPivot(90f, dstRect.center);
             }
             if (tile != null && tile.prefabData.prefab && tile.prefabData.showPrefabPreviewInTilePalette)
             {
                 Texture2D assetPreview = AssetPreview.GetAssetPreview(tile.prefabData.prefab);
                 if (assetPreview)
                 {
                     GUI.DrawTexture(dstRect, assetPreview, ScaleMode.ScaleToFit);
                 }
                 else
                 {
                     GUI.DrawTextureWithTexCoords(dstRect, tileset.AtlasTexture, customUV == default(Rect) && tile != null ? tile.uv : customUV, true);
                 }
             }
             else
             {
                 GUI.DrawTextureWithTexCoords(dstRect, tileset.AtlasTexture, customUV == default(Rect) && tile != null ? tile.uv : customUV, true);
             }
             GUI.matrix = Matrix4x4.identity;
         }
     }
 }
예제 #3
0
        public bool AutotileWith(Tileset tileset, int selfBrushId, uint otherTileData)
        {
            int otherBrushId = (int)((uint)(otherTileData & Tileset.k_TileDataMask_BrushId) >> 16);

            if (otherBrushId != Tileset.k_BrushId_Default && otherBrushId != selfBrushId && (AutotilingMode & eAutotilingMode.SkipOtherBrushes) != 0)
            {
                return(false);
            }
            if ((AutotilingMode & eAutotilingMode.EmptyCells) != 0 && otherTileData == Tileset.k_TileData_Empty)
            {
                return(true);
            }
            if ((AutotilingMode & eAutotilingMode.Group) != 0)
            {
                Tile tile = tileset.GetTile((int)(otherTileData & Tileset.k_TileDataMask_TileId));
                if (tile != null && Tileset.GetGroupAutotiling(Group, tile.autilingGroup))
                {
                    return(true);
                }
            }
            return(AutotileWith(selfBrushId, otherBrushId));
        }
예제 #4
0
        /// <summary>
        /// Returns a sprite for the tileId in the tileset and using the pixelsPerUnit specified (or the tileset pixels per units if the values is <= 0)
        /// </summary>
        public static Sprite GetOrCreateTileSprite(Tileset tileset, int tileId, float pixelsPerUnit = 0)
        {
            Sprite sprite = null;

            if (pixelsPerUnit <= 0)
            {
                pixelsPerUnit = tileset.PixelsPerUnit;
            }
            Tile tile = tileset.GetTile(tileId);

            if (tile != null)
            {
                Vector2 atlasSize  = new Vector2(tileset.AtlasTexture.width, tileset.AtlasTexture.height);
                Rect    spriteUV   = new Rect(Vector2.Scale(tile.uv.position, atlasSize), Vector2.Scale(tile.uv.size, atlasSize));
                string  spriteName = tileset.name + "_" + tileId + "_" + pixelsPerUnit;
                if (!s_spriteCache.TryGetValue(spriteName, out sprite) || !sprite)
                {
                    sprite      = Sprite.Create(tileset.AtlasTexture, spriteUV, new Vector2(.5f, .5f), pixelsPerUnit);
                    sprite.name = spriteName;
                    s_spriteCache[spriteName] = sprite;
                }
            }
            return(sprite);
        }
        private void DisplayCollider()
        {
            Event e = Event.current;

            if (Tileset.SelectedBrushId != Tileset.k_BrushId_Default)
            {
                EditorGUILayout.LabelField("Brush tile editing not allowed", EditorStyles.boldLabel);
                return;
            }

            bool isMultiselection = Tileset.TileSelection != null;
            bool saveChanges      = false;
            Tile selectedTile     = isMultiselection ? Tileset.Tiles[(int)(Tileset.TileSelection.selectionData[0] & Tileset.k_TileDataMask_TileId)] : Tileset.SelectedTile;

            if (e.type == EventType.MouseDown)
            {
                m_isDragging = true;
                if (selectedTile.collData.vertices != null)
                {
                    m_savedVertexData = new Vector2[selectedTile.collData.vertices.Length];
                    selectedTile.collData.vertices.CopyTo(m_savedVertexData, 0);
                }
            }
            else if (e.type == EventType.MouseUp)
            {
                m_isDragging = false;
            }

            Tileset.BackgroundColor = EditorGUILayout.ColorField(Tileset.BackgroundColor);
            if (m_prevBgColor != Tileset.BackgroundColor || Styles.Instance.colliderBgStyle.normal.background == null)
            {
                m_prevBgColor = Tileset.BackgroundColor;
                if (Styles.Instance.colliderBgStyle.normal.background == null)
                {
                    Styles.Instance.colliderBgStyle.normal.background = new Texture2D(1, 1)
                    {
                        hideFlags = HideFlags.DontSave
                    }
                }
                ;
                Styles.Instance.colliderBgStyle.normal.background.SetPixel(0, 0, Tileset.BackgroundColor);
                Styles.Instance.colliderBgStyle.normal.background.Apply();
            }

            float aspectRatio = Tileset.TilePxSize.x / Tileset.TilePxSize.y;
            float padding     = 2; // pixel size of the border around the tile
            //Rect rCollArea = GUILayoutUtility.GetRect(1, 1, GUILayout.Width(EditorGUIUtility.currentViewWidth), GUILayout.Height(EditorGUIUtility.currentViewWidth / aspectRatio));
            Rect rCollArea = GUILayoutUtility.GetRect(1, 1, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true));

            GUI.BeginGroup(rCollArea, Styles.Instance.colliderBgStyle);
            if (e.type == EventType.Repaint)
            {
                float pixelSize = rCollArea.width / (Tileset.TilePxSize.x + 2 * padding);
                m_mousePos     = e.mousePosition;
                m_rTile        = new Rect(padding * pixelSize, padding * pixelSize, rCollArea.width - 2 * padding * pixelSize, (rCollArea.width / aspectRatio) - 2 * padding * pixelSize);
                m_rTile.height = Mathf.Min(m_rTile.height, rCollArea.height - 2 * padding * pixelSize);
                m_rTile.width  = (m_rTile.height * aspectRatio);
            }
            GUI.color = new Color(1f, 1f, 1f, 0.1f);
            GUI.DrawTexture(m_rTile, EditorGUIUtility.whiteTexture);
            GUI.color = Color.white;
            if (isMultiselection)
            {
                foreach (uint tileData in Tileset.TileSelection.selectionData)
                {
                    int  tileId = (int)(tileData & Tileset.k_TileDataMask_TileId);
                    Tile tile   = Tileset.GetTile(tileId);
                    if (tile != null)
                    {
                        GUI.color = new Color(1f, 1f, 1f, 1f / Tileset.TileSelection.selectionData.Count);
                        GUI.DrawTextureWithTexCoords(m_rTile, Tileset.AtlasTexture, tile.uv);
                    }
                }
                GUI.color = Color.white;
            }
            else
            {
                GUI.DrawTextureWithTexCoords(m_rTile, Tileset.AtlasTexture, selectedTile.uv);
            }

            Color savedHandleColor = Handles.color;

            if (selectedTile.collData.type != eTileCollider.None)
            {
                Vector2[] collVertices = selectedTile.collData.type == eTileCollider.Full ? s_fullCollTileVertices : selectedTile.collData.vertices;
                if (collVertices == null || collVertices.Length == 0)
                {
                    collVertices = selectedTile.collData.vertices = new Vector2[s_fullCollTileVertices.Length];
                    Array.Copy(s_fullCollTileVertices, collVertices, s_fullCollTileVertices.Length);
                    EditorUtility.SetDirty(Tileset);
                }

                // Fix and snap positions
                for (int i = 0; i < collVertices.Length; ++i)
                {
                    Vector2 s0 = collVertices[i];
                    s0.x            = Mathf.Clamp01(Mathf.Round(s0.x * Tileset.TilePxSize.x) / Tileset.TilePxSize.x);
                    s0.y            = Mathf.Clamp01(Mathf.Round(s0.y * Tileset.TilePxSize.y) / Tileset.TilePxSize.y);
                    collVertices[i] = s0;
                }

                // Draw edges
                Vector3[] polyEdges = new Vector3[collVertices.Length + 1];
                for (int i = 0; i < collVertices.Length; ++i)
                {
                    Vector2 s0 = collVertices[i];
                    s0.x = m_rTile.x + m_rTile.width * s0.x; s0.y = m_rTile.yMax - m_rTile.height * s0.y;
                    Vector2 s1 = collVertices[(i + 1) % collVertices.Length];
                    s1.x = m_rTile.x + m_rTile.width * s1.x; s1.y = m_rTile.yMax - m_rTile.height * s1.y;

                    polyEdges[i]     = s0;
                    polyEdges[i + 1] = s1;

                    Handles.color = Color.green;
                    Handles.DrawLine(s0, s1);
                    //Draw normals
                    {
                        Handles.color = Color.white;
                        Vector3 normPos = (s0 + s1) / 2f;
                        Handles.DrawLine(normPos, normPos + Vector3.Cross(s1 - s0, Vector3.forward).normalized *m_rTile.yMin);
                    }

                    Handles.color = savedHandleColor;
                }

                float pixelSize = m_rTile.width / Tileset.TilePxSize.x;
                if (selectedTile.collData.type == eTileCollider.Polygon)
                {
                    bool isAddingVertexOn   = !m_isDragging && e.shift && m_activeVertexIdx == -1;
                    bool isRemovingVertexOn = !m_isDragging && ((Application.platform == RuntimePlatform.OSXEditor)? e.command : e.control) && collVertices.Length > 3;
                    if (isRemovingVertexOn && m_activeVertexIdx != -1 && e.type == EventType.MouseUp)
                    {
                        selectedTile.collData.vertices = new Vector2[collVertices.Length - 1];
                        for (int i = 0, j = 0; i < collVertices.Length; ++i)
                        {
                            if (i == m_activeVertexIdx)
                            {
                                continue;
                            }
                            selectedTile.collData.vertices[j] = collVertices[i];
                            ++j;
                        }
                        collVertices      = selectedTile.collData.vertices;
                        m_activeVertexIdx = -1;
                    }

                    float minDist = float.MaxValue;
                    if (!m_isDragging)
                    {
                        m_activeVertexIdx = -1;
                    }
                    for (int i = 0; i < collVertices.Length; ++i)
                    {
                        Vector2 s0 = collVertices[i];
                        s0.x = m_rTile.x + m_rTile.width * s0.x;
                        s0.y = m_rTile.yMax - m_rTile.height * s0.y;

                        if (m_isDragging)
                        {
                            if (i == m_activeVertexIdx)
                            {
                                s0   = m_mousePos;
                                s0  -= m_rTile.position;
                                s0.x = Mathf.Clamp(Mathf.Round(s0.x / pixelSize) * pixelSize, 0, m_rTile.width);
                                s0.y = Mathf.Clamp(Mathf.Round(s0.y / pixelSize) * pixelSize, 0, m_rTile.height);
                                s0  += m_rTile.position;
                                collVertices[i].x = Mathf.Clamp01((s0.x - m_rTile.x) / m_rTile.width);
                                collVertices[i].y = Mathf.Clamp01((s0.y - m_rTile.yMax) / -m_rTile.height);
                            }
                        }
                        else
                        {
                            float dist = Vector2.Distance(m_mousePos, s0);
                            if (dist <= minDist && dist < Styles.Instance.collVertexHandleStyle.normal.background.width)
                            {
                                minDist           = dist;
                                m_activeVertexIdx = i;
                            }
                        }

                        if (e.type == EventType.Repaint)
                        {
                            if (i == m_activeVertexIdx)
                            {
                                Styles.Instance.vertexCoordStyle.fontSize = (int)(Mathf.Min(10f, m_rTile.yMin / 2f));
                                GUI.Label(new Rect(0, 0, m_rTile.width, m_rTile.yMin), Vector2.Scale(collVertices[i], Tileset.TilePxSize).ToString(), Styles.Instance.vertexCoordStyle);
                            }
                            GUI.color = m_activeVertexIdx == i ? (isRemovingVertexOn ? Color.red : Color.cyan) : new Color(0.7f, 0.7f, 0.7f, 0.8f);
                            Styles.Instance.collVertexHandleStyle.Draw(new Rect(s0.x - Styles.Instance.collVertexHandleStyle.normal.background.width / 2, s0.y - Styles.Instance.collVertexHandleStyle.normal.background.height / 2, 1, 1), i.ToString(), false, false, false, false);
                            GUI.color = Color.white;
                        }
                    }

                    if (isAddingVertexOn)
                    {
                        int     segmentIdx;
                        Vector2 newVertexPos = ClosestPointToPolyLine(polyEdges, out segmentIdx);

                        if (e.type == EventType.MouseUp)
                        {
                            selectedTile.collData.vertices = new Vector2[collVertices.Length + 1];
                            segmentIdx = (segmentIdx + 1) % selectedTile.collData.vertices.Length;
                            for (int i = 0, j = 0; i < selectedTile.collData.vertices.Length; ++i)
                            {
                                if (segmentIdx == i)
                                {
                                    newVertexPos.x = Mathf.Clamp(Mathf.Round(newVertexPos.x / pixelSize) * pixelSize, m_rTile.x, m_rTile.xMax);
                                    newVertexPos.y = Mathf.Clamp(Mathf.Round(newVertexPos.y / pixelSize) * pixelSize, m_rTile.y, m_rTile.yMax);
                                    selectedTile.collData.vertices[i].x = Mathf.Clamp01((newVertexPos.x - m_rTile.x) / m_rTile.width);
                                    selectedTile.collData.vertices[i].y = Mathf.Clamp01((newVertexPos.y - m_rTile.yMax) / -m_rTile.height);
                                }
                                else
                                {
                                    selectedTile.collData.vertices[i] = collVertices[j];
                                    ++j;
                                }
                            }
                            collVertices      = selectedTile.collData.vertices;
                            m_activeVertexIdx = -1;
                        }
                        else if (e.type == EventType.Repaint)
                        {
                            GUI.color = new Color(0.7f, 0.7f, 0.7f, 0.8f);
                            Styles.Instance.collVertexHandleStyle.Draw(new Rect(newVertexPos.x - Styles.Instance.collVertexHandleStyle.normal.background.width / 2, newVertexPos.y - Styles.Instance.collVertexHandleStyle.normal.background.height / 2, 1, 1), segmentIdx.ToString(), false, false, false, false);
                            GUI.color = Color.white;
                        }
                    }
                }

                if (e.type == EventType.MouseUp)
                {
                    saveChanges = true;
                    //remove duplicated vertex
                    selectedTile.collData.vertices = selectedTile.collData.vertices.Distinct().ToArray();
                    if (selectedTile.collData.vertices.Length <= 2)
                    {
                        selectedTile.collData.vertices = m_savedVertexData;
                    }
                    //snap vertex positions
                    selectedTile.collData.SnapVertices(Tileset);
                }
            }

            GUI.EndGroup();

            if (GUILayout.Button("Reverse Normals"))
            {
                selectedTile.collData.vertices = selectedTile.collData.vertices.Reverse().ToArray();
            }

            EditorGUILayout.Space();

            string helpInfo =
                "  - Click and drag over a vertex to move it" + "\n" +
                "  - Hold Shift + Click for adding a new vertex" + "\n" +
                "  - Hold " + ((Application.platform == RuntimePlatform.OSXEditor)? "Command" : "Ctrl") + " + Click for removing a vertex. (should be more than 3)" + "\n" +
                "  - Check the normals for each edge. The normal is displayed in the collision side" + "\n" +
                "";

            s_showHelp = EditorGUILayout.Foldout(s_showHelp, "Help");
            if (s_showHelp)
            {
                EditorGUILayout.HelpBox(helpInfo, MessageType.Info);
            }

            //+++ Collider Settings
            float savedLabelWidth = EditorGUIUtility.labelWidth;

            EditorGUIUtility.labelWidth = 40;
            if (isMultiselection)
            {
                EditorGUILayout.LabelField("* Multi-selection Edition", EditorStyles.boldLabel);
            }
            EditorGUILayout.BeginHorizontal(GUILayout.MinWidth(140));
            {
                EditorGUILayout.LabelField("Collider Data", EditorStyles.boldLabel);
                if (GUILayout.Button("Copy", GUILayout.Width(50)))
                {
                    m_copiedColliderData = selectedTile.collData.Clone();
                }
                if (GUILayout.Button("Paste", GUILayout.Width(50)))
                {
                    selectedTile.collData = m_copiedColliderData.Clone();
                    saveChanges           = true;
                }
            }
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.Space();
            EditorGUIUtility.labelWidth = 100;
            EditorGUI.BeginChangeCheck();

            //selectedTile.collData.type = (eTileCollider)EditorGUILayout.EnumPopup("Collider Type", selectedTile.collData.type);
            EditorGUILayout.LabelField("Collider Type:", EditorStyles.boldLabel);
            EditorGUI.indentLevel += 2;
            string[] tileColliderNames = System.Enum.GetNames(typeof(eTileCollider));

            selectedTile.collData.type = (eTileCollider)GUILayout.Toolbar((int)selectedTile.collData.type, tileColliderNames);
            EditorGUI.indentLevel     -= 2;

            saveChanges |= EditorGUI.EndChangeCheck();
            EditorGUIUtility.labelWidth = savedLabelWidth;
            //---

            //Save changes
            if (saveChanges)
            {
                if (isMultiselection)
                {
                    for (int i = 0; i < Tileset.TileSelection.selectionData.Count; ++i)
                    {
                        Tileset.Tiles[(int)(Tileset.TileSelection.selectionData[i] & Tileset.k_TileDataMask_TileId)].collData = selectedTile.collData.Clone();
                    }
                }
                EditorUtility.SetDirty(Tileset);
                //Refresh selected tilemap
                Tilemap selectedTilemap = Selection.activeGameObject? Selection.activeGameObject.GetComponent <Tilemap>() : null;
                if (selectedTilemap)
                {
                    selectedTilemap.Refresh(false, true);
                }
            }
        }

        /// <summary>
        //     Get the point on a polyline (in 3D space) which is closest to the current
        //     mouse position. And returns the segment index ( the vertex index of the segment with the closest point )
        /// </summary>
        /// <param name="vertices"></param>
        /// <param name="closestSegmentIdx"></param>
        /// <returns></returns>
        Vector3 ClosestPointToPolyLine(Vector3[] vertices, out int closestSegmentIdx)
        {
            float minDist = float.MaxValue;

            closestSegmentIdx = 0;
            for (int i = 0; i < vertices.Length - 1; ++i)
            {
                float dist = HandleUtility.DistanceToLine(vertices[i], vertices[i + 1]);
                if (dist < minDist)
                {
                    minDist           = dist;
                    closestSegmentIdx = i;
                }
            }
            return(HandleUtility.ClosestPointToPolyLine(vertices));
        }
예제 #6
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 ||
                    brushId == 0)                //NOTE: because of the autotiling mode, neighbour tiles could be affected by this change, even if the tile is not a brush
                {
                    if (!s_currUpdatedTilechunk) // avoid this is chunks is being Updated from FillMeshData
                    {
                        // Refresh Neighbors ( and itself if needed )
                        for (int yf = -1; yf <= 1; ++yf)
                        {
                            for (int xf = -1; xf <= 1; ++xf)
                            {
                                if ((xf | yf) == 0)
                                {
                                    if (brushId > 0)
                                    {
                                        // Refresh itself
                                        tileData = (tileData & ~Tileset.k_TileFlag_Updated);
                                    }
                                }
                                else
                                {
                                    int          gx               = (locGridX + xf);
                                    int          gy               = (locGridY + yf);
                                    int          idx              = gy * m_width + gx;
                                    bool         isInsideChunk    = (gx >= 0 && gx < m_width && gy >= 0 && gy < m_height);
                                    uint         neighborTileData = isInsideChunk ? m_tileDataList[idx] : ParentTilemap.GetTileData(GridPosX + locGridX + xf, GridPosY + locGridY + yf);
                                    int          neighborBrushId  = (int)((neighborTileData & Tileset.k_TileDataMask_BrushId) >> 16);
                                    TilesetBrush neighborBrush    = ParentTilemap.Tileset.FindBrush(neighborBrushId);
                                    if (neighborBrush != null &&
                                        (neighborBrush.AutotileWith(ParentTilemap.Tileset, neighborBrushId, tileData) || neighborBrush.AutotileWith(ParentTilemap.Tileset, neighborBrushId, m_tileDataList[tileIdx])))
                                    {
                                        neighborTileData = (neighborTileData & ~Tileset.k_TileFlag_Updated); // force a refresh
                                        if (isInsideChunk)
                                        {
                                            m_tileDataList[idx] = neighborTileData;
                                        }
                                        else
                                        {
                                            ParentTilemap.SetTileData(GridPosX + gx, GridPosY + gy, neighborTileData);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                else if (brushId > 0)
                {
                    // Refresh itself
                    tileData = (tileData & ~Tileset.k_TileFlag_Updated);
                }

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

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

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

                if (!STETilemap.DisableTilePrefabCreation)
                {
                    // Create tile Objects
                    if (tile != null && tile.prefabData.prefab != null)
                    {
                        CreateTileObject(tileIdx, tile.prefabData);
                    }
                    else
                    {
                        DestroyTileObject(tileIdx);
                    }
                }

                TilesetBrush brush = ParentTilemap.Tileset.FindBrush(brushId);
                if (brushId != prevBrushId)
                {
                    TilesetBrush prevBrush = ParentTilemap.Tileset.FindBrush(prevBrushId);
                    if (prevBrush != null)
                    {
                        prevBrush.OnErase(this, locGridX, locGridY, tileData, prevBrushId);
                    }
                }
                if (brush != null)
                {
                    tileData = brush.OnPaint(this, locGridX, locGridY, tileData);
                }
            }
        }
예제 #7
0
        private void UpdateMeshVertexColor()
        {
            //Debug.Log( "[" + ParentTilemap.name + "] FillData -> " + name);
            if (!Tileset || !Tileset.AtlasTexture)
            {
                return;
            }

            int totalTiles = m_width * m_height;

            if (s_colors32 == null)
            {
                s_colors32 = new List <Color32>(totalTiles * 4);
            }
            else
            {
                s_colors32.Clear();
            }

            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);
                        }

                        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 )
                                {
                                    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)
                            {
                                //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.
                                {
                                    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;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
예제 #8
0
        /*
         * private void DummyDeepProfilingFix()
         * {
         *  // For some reason, in Unity 2017.3.1f1, the Deep Profiling crashes unless FillMeshData call any method, even a dummy method like this
         *  // Other weird thing is, the crash doesn't happens if one case of the switch statement is commented
         *  // FINALLY: the fix was to change the Switch for if-else statements. I keep this notes just in case to remember about this weird issue.
         * }
         */

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

            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 (tileId >= 0 && tile == null && brushId <= 0)
                        {
                            Debug.LogWarning(ParentTilemap.name + "\\" + name + ": TileId " + tileId + " not found! GridPos(" + (GridPosX + tx) + "," + (GridPosY + ty) + ") tilaData 0x" + tileData.ToString("X"));
                            m_tileDataList[tileIdx] = Tileset.k_TileData_Empty;
                        }
                        if (brushId > 0)
                        {
                            tileBrush = Tileset.FindBrush(brushId);
                            if (tileBrush == null)
                            {
                                Debug.LogWarning(ParentTilemap.name + "\\" + name + ": BrushId " + brushId + " not found! GridPos(" + (GridPosX + tx) + "," + (GridPosY + 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) // FIX Deep Profiling crash in Unity 2017.3.1f1 see: DummyDeepProfilingFix notes
                                        {
                                            if (i == 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);
                                            }
                                            else if (i == 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));
                                            }
                                            else if (i == 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));
                                            }
                                            else if (i == 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);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            //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);
        }
예제 #9
0
        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 (tile != null)
                        {
#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
                            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 (neighborTileId != Tileset.k_TileId_Empty)
                                        {
                                            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];
                    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);
        }