private ReorderableList CreateTilemapReorderableList() { ReorderableList reordList = new ReorderableList(serializedObject, serializedObject.FindProperty("m_tilemaps"), true, true, true, true); reordList.displayAdd = reordList.displayRemove = true; reordList.drawHeaderCallback = (Rect rect) => { EditorGUI.LabelField(rect, "Tilemaps", EditorStyles.boldLabel); Texture2D btnTexture = reordList.elementHeight == 0f ? EditorGUIUtility.FindTexture("winbtn_win_max_h") : EditorGUIUtility.FindTexture("winbtn_win_min_h"); if (GUI.Button(new Rect(rect.x + rect.width - rect.height, rect.y, rect.height, rect.height), btnTexture, EditorStyles.label)) { GUI.changed = true; reordList.elementHeight = reordList.elementHeight == 0f ? 21f : 0f; reordList.draggable = reordList.elementHeight > 0f; reordList.displayAdd = reordList.draggable; reordList.displayRemove = reordList.draggable; } }; var tilemapTilemapSerialized = new Dictionary <STETilemap, SerializedObject>(); var tilemapTilemapObjectSerialized = new Dictionary <SerializedObject, SerializedObject>(); reordList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => { if (reordList.elementHeight == 0) { return; } var element = reordList.serializedProperty.GetArrayElementAtIndex(index); rect.y += 2; STETilemap tilemap = element.objectReferenceValue as STETilemap; if (tilemap) { SerializedObject tilemapSerialized; SerializedObject tilemapObjSerialized; if (!tilemapTilemapSerialized.TryGetValue(tilemap, out tilemapSerialized)) { tilemapTilemapSerialized[tilemap] = tilemapSerialized = new SerializedObject(tilemap); } if (!tilemapTilemapObjectSerialized.TryGetValue(tilemapSerialized, out tilemapObjSerialized)) { tilemapTilemapObjectSerialized[tilemapSerialized] = tilemapObjSerialized = new SerializedObject(tilemapSerialized.FindProperty("m_GameObject").objectReferenceValue); } Rect rToggle = new Rect(rect.x, rect.y, 16f, EditorGUIUtility.singleLineHeight); Rect rName = new Rect(rect.x + 20f, rect.y, rect.width - 130f - 20f, EditorGUIUtility.singleLineHeight); Rect rColliders = new Rect(rect.x + rect.width - 125f, rect.y, 125f, EditorGUIUtility.singleLineHeight); Rect rSortingLayer = new Rect(rect.x + rect.width - 125f, rect.y, 80f, EditorGUIUtility.singleLineHeight); Rect rSortingOrder = new Rect(rect.x + rect.width - 40f, rect.y, 40f, EditorGUIUtility.singleLineHeight); tilemap.IsVisible = EditorGUI.Toggle(rToggle, GUIContent.none, tilemap.IsVisible, STEditorStyles.Instance.visibleToggleStyle); EditorGUI.PropertyField(rName, tilemapObjSerialized.FindProperty("m_Name"), GUIContent.none); if (TilemapEditor.EditMode == TilemapEditor.eEditMode.Collider) { SerializedProperty colliderTypeProperty = tilemapSerialized.FindProperty("ColliderType"); string[] colliderTypeNames = new List <string>(System.Enum.GetNames(typeof(eColliderType)).Select(x => x.Replace('_', ' '))).ToArray(); EditorGUI.BeginChangeCheck(); colliderTypeProperty.intValue = GUI.Toolbar(rColliders, colliderTypeProperty.intValue, colliderTypeNames); if (EditorGUI.EndChangeCheck()) { tilemapSerialized.ApplyModifiedProperties(); tilemap.Refresh(false, true); } } else { // Sorting Layer and Order in layer EditorGUI.BeginChangeCheck(); EditorGUI.PropertyField(rSortingLayer, tilemapSerialized.FindProperty("m_sortingLayer"), GUIContent.none); EditorGUI.PropertyField(rSortingOrder, tilemapSerialized.FindProperty("m_orderInLayer"), GUIContent.none); tilemapSerialized.FindProperty("m_orderInLayer").intValue = (tilemapSerialized.FindProperty("m_orderInLayer").intValue << 16) >> 16; // convert from int32 to int16 keeping sign if (EditorGUI.EndChangeCheck()) { tilemapSerialized.ApplyModifiedProperties(); tilemap.RefreshChunksSortingAttributes(); SceneView.RepaintAll(); } //--- } if (GUI.changed) { tilemapObjSerialized.ApplyModifiedProperties(); } } }; reordList.onReorderCallback = (ReorderableList list) => { var targetObj = target as TilemapGroup; int sibilingIdx = 0; foreach (STETilemap tilemap in targetObj.Tilemaps) { tilemap.transform.SetSiblingIndex(sibilingIdx++); } Repaint(); }; reordList.onSelectCallback = (ReorderableList list) => { m_selectedIndexProp.intValue = reordList.index; serializedObject.ApplyModifiedProperties(); GUI.changed = true; TileSelectionWindow.RefreshIfVisible(); TilePropertiesWindow.RefreshIfVisible(); }; reordList.onAddCallback = (ReorderableList list) => { var targetObj = target as TilemapGroup; Undo.RegisterCompleteObjectUndo(targetObj, "New Tilemap"); GameObject obj = new GameObject(); Undo.RegisterCreatedObjectUndo(obj, "New Tilemap"); STETilemap newTilemap = obj.AddComponent <STETilemap>(); obj.transform.parent = targetObj.transform; obj.name = GameObjectUtility.GetUniqueNameForSibling(obj.transform.parent, "New Tilemap"); STETilemap copiedTilemap = targetObj.SelectedTilemap; if (copiedTilemap) { UnityEditorInternal.ComponentUtility.CopyComponent(copiedTilemap); UnityEditorInternal.ComponentUtility.PasteComponentValues(newTilemap); obj.name = GameObjectUtility.GetUniqueNameForSibling(obj.transform.parent, copiedTilemap.name); } }; reordList.onRemoveCallback = (ReorderableList list) => { m_tilemapRemovingList.Add(m_target.SelectedTilemap.gameObject); }; return(reordList); }
private void OnToolSelected_BrushToolbar(ToolbarControl source, int selectedToolIdx, int prevSelectedToolIdx) { ToolIcons.eToolIcon toolIcon = (ToolIcons.eToolIcon)selectedToolIdx; switch (toolIcon) { case ToolIcons.eToolIcon.Pencil: TilemapEditor.s_brushMode = TilemapEditor.eBrushMode.Paint; Tools.current = Tool.None; break; case ToolIcons.eToolIcon.Erase: TilemapEditor.s_brushMode = TilemapEditor.eBrushMode.Erase; brushPaintToolbar.TriggerButton(0); Tools.current = Tool.None; break; case ToolIcons.eToolIcon.Fill: TilemapEditor.s_brushMode = TilemapEditor.eBrushMode.Fill; brushPaintToolbar.TriggerButton(0); Tools.current = Tool.None; break; case ToolIcons.eToolIcon.FlipV: BrushBehaviour.SFlipV(); Tools.current = Tool.None; source.SelectedIdx = prevSelectedToolIdx; break; case ToolIcons.eToolIcon.FlipH: BrushBehaviour.SFlipH(); Tools.current = Tool.None; source.SelectedIdx = prevSelectedToolIdx; break; case ToolIcons.eToolIcon.Rot90: BrushBehaviour.SRot90(); Tools.current = Tool.None; source.SelectedIdx = prevSelectedToolIdx; break; case ToolIcons.eToolIcon.Info: TilemapEditor.s_displayHelpBox = !TilemapEditor.s_displayHelpBox; Tools.current = Tool.None; source.SelectedIdx = prevSelectedToolIdx; source.SetHighlight(selectedToolIdx, TilemapEditor.s_displayHelpBox); break; case ToolIcons.eToolIcon.Refresh: TilemapGroup tilemapGroup = Selection.activeGameObject.GetComponent <TilemapGroup>(); if (tilemapGroup) { foreach (STETilemap tilemap in tilemapGroup.Tilemaps) { tilemap.Refresh(true, true, true, true); } } else { STETilemap tilemap = Selection.activeGameObject.GetComponent <STETilemap>(); if (tilemap) { tilemap.Refresh(true, true, true, true); } } Tools.current = Tool.None; source.SelectedIdx = prevSelectedToolIdx; break; } }
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))) { s_copiedColliderData = selectedTile.collData.Clone(); } if (GUILayout.Button("Paste", GUILayout.Width(50))) { selectedTile.collData = s_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 STETilemap selectedTilemap = Selection.activeGameObject? Selection.activeGameObject.GetComponent <STETilemap>() : 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)); }