using UnityEngine; using UnityEditor; using System.Linq; using System.Collections.Generic; namespace IsoTools.Internal { static class IsoEditorUtils { // --------------------------------------------------------------------- // // Inspector // // --------------------------------------------------------------------- public static void DoWithMixedValue(bool mixed, System.Action act) { var last_show_mixed_value = EditorGUI.showMixedValue; EditorGUI.showMixedValue = mixed; try { act(); } finally { EditorGUI.showMixedValue = last_show_mixed_value; } } public static void DoWithEnabledGUI(bool enabled, System.Action act) { EditorGUI.BeginDisabledGroup(!enabled); try { act(); } finally { EditorGUI.EndDisabledGroup(); } } public static void DrawWorldProperties(IsoWorld[] iso_worlds) { if ( iso_worlds.Length > 0 ) { var so = new SerializedObject(iso_worlds); var so_prop = so.GetIterator(); if ( so_prop.NextVisible(true) ) { while ( so_prop.NextVisible(true) ) { EditorGUILayout.PropertyField(so_prop); } } if ( GUI.changed ) { so.ApplyModifiedProperties(); } } } public static void DrawSelfWorldProperty(IsoWorld[] iso_worlds) { if ( iso_worlds.Length > 0 ) { var mixed_world = iso_worlds.GroupBy(p => p).Count() > 1; EditorGUILayout.Space(); IsoEditorUtils.DoWithEnabledGUI(false, () => { IsoEditorUtils.DoWithMixedValue(mixed_world, () => { EditorGUILayout.ObjectField( "Current IsoWorld", iso_worlds.First(), typeof(IsoWorld), true); }); }); } } // --------------------------------------------------------------------- // // Editor // // --------------------------------------------------------------------- public static float ZMoveIsoObjects( bool move, IsoWorld iso_world, Dictionary> all_iso_objects, Dictionary> all_other_objects, float delta) { List iso_objects; if ( all_iso_objects.TryGetValue(iso_world, out iso_objects) ) { if ( move ) { Undo.RecordObjects( iso_objects.ToArray(), iso_objects.Count > 1 ? "Move IsoObjects" : "Move IsoObject"); } var snapping_z = false; if ( IsSnapByObjectsEnabled(iso_world) ) { List other_objects; if ( all_other_objects.TryGetValue(iso_world, out other_objects) && other_objects.Count > 0 ) { foreach ( var iso_object in iso_objects ) { var iso_orig_z = iso_object.positionZ; var result_p_z = iso_orig_z + delta; foreach ( var other in other_objects ) { var x_snap_overlaps = IsoEditorUtils.IsSnapOverlaps( iso_world.snappingDistance, iso_object.positionX, iso_object.sizeX, other.positionX, other.sizeX); var y_snap_overlaps = IsoEditorUtils.IsSnapOverlaps( iso_world.snappingDistance, iso_object.positionY, iso_object.sizeY, other.positionY, other.sizeY); if ( x_snap_overlaps && y_snap_overlaps ){ var new_snapping_z = !snapping_z && IsoEditorUtils.IsSnapOverlaps( iso_world.snappingDistance, result_p_z, iso_object.sizeZ, other.positionZ, other.sizeZ) ? IsoEditorUtils.SnapProcess( iso_world.snappingDistance, ref result_p_z, iso_object.sizeZ, other.positionZ, other.sizeZ) : false; if ( new_snapping_z && IsSnapByObjectAllowed(iso_object, other) ) { delta = result_p_z - iso_orig_z; snapping_z = true; break; } } } if ( snapping_z ) { break; } } } } if ( IsSnapByCellsEnabled(iso_world) && !snapping_z ) { foreach ( var iso_object in iso_objects ) { var iso_orig_z = iso_object.positionZ; var result_p_z = iso_orig_z + delta; var new_snapping_z = IsoEditorUtils.SnapProcess( iso_world.snappingDistance, ref result_p_z, iso_object.sizeZ, iso_object.tilePositionZ, 1.0f); if ( new_snapping_z ) { delta = result_p_z - iso_orig_z; snapping_z = true; break; } } } return iso_objects.Aggregate(0.0f, (AccIn, iso_object) => { var iso_orig_z = iso_object.positionZ; var result_p_z = iso_orig_z + delta; if ( move ) { iso_object.positionZ = IsoUtils.FloatBeautifier(result_p_z); } var z_delta = result_p_z - iso_orig_z; return Mathf.Abs(z_delta) > Mathf.Abs(AccIn) ? z_delta : AccIn; }); } return delta; } public static Vector3 XYMoveIsoObjects( bool move, IsoWorld iso_world, Dictionary> all_iso_objects, Dictionary> all_other_objects, Vector3 iso_delta) { List iso_objects; if ( all_iso_objects.TryGetValue(iso_world, out iso_objects) ) { if ( move ) { Undo.RecordObjects( iso_objects.ToArray(), iso_objects.Count > 1 ? "Move IsoObjects" : "Move IsoObject"); } var snapping_x = false; var snapping_y = false; if ( IsSnapByObjectsEnabled(iso_world) ) { List other_objects; if ( all_other_objects.TryGetValue(iso_world, out other_objects) && other_objects.Count > 0 ) { foreach ( var iso_object in iso_objects ) { var iso_orig_p = iso_object.position; var result_pos_iso = iso_orig_p + iso_delta; foreach ( var other in other_objects ) { var z_snap_overlaps = IsoEditorUtils.IsSnapOverlaps( iso_world.snappingDistance, iso_object.positionZ, iso_object.sizeZ, other.positionZ, other.sizeZ); if ( z_snap_overlaps ) { var new_snapping_x = !snapping_x && IsoEditorUtils.IsSnapOverlaps( iso_world.snappingDistance, result_pos_iso.y, iso_object.sizeY, other.positionY, other.sizeY) ? IsoEditorUtils.SnapProcess( iso_world.snappingDistance, ref result_pos_iso.x, iso_object.sizeX, other.positionX, other.sizeX) : false; var new_snapping_y = !snapping_y && IsoEditorUtils.IsSnapOverlaps( iso_world.snappingDistance, result_pos_iso.x, iso_object.sizeX, other.positionX, other.sizeX) ? IsoEditorUtils.SnapProcess( iso_world.snappingDistance, ref result_pos_iso.y, iso_object.sizeY, other.positionY, other.sizeY) : false; if ( (new_snapping_x || new_snapping_y) && IsSnapByObjectAllowed(iso_object, other) ) { if ( new_snapping_x ) { snapping_x = true; iso_delta.x = result_pos_iso.x - iso_orig_p.x; iso_delta.y = result_pos_iso.y - iso_orig_p.y; } if ( new_snapping_y ) { snapping_y = true; iso_delta.x = result_pos_iso.x - iso_orig_p.x; iso_delta.y = result_pos_iso.y - iso_orig_p.y; } if ( snapping_x && snapping_y ) { break; } } } } if ( snapping_x && snapping_y ) { break; } } } } if ( IsSnapByCellsEnabled(iso_world) && !snapping_x && !snapping_y ) { foreach ( var iso_object in iso_objects ) { var iso_orig_p = iso_object.position; var result_pos_iso = iso_orig_p + iso_delta; var new_snapping_x = IsoEditorUtils.SnapProcess( iso_world.snappingDistance, ref result_pos_iso.x, iso_object.sizeX, iso_object.tilePositionX, 1.0f); var new_snapping_y = IsoEditorUtils.SnapProcess( iso_world.snappingDistance, ref result_pos_iso.y, iso_object.sizeY, iso_object.tilePositionY, 1.0f); if ( new_snapping_x || new_snapping_y ) { if ( new_snapping_x ) { iso_delta.x = result_pos_iso.x - iso_orig_p.x; iso_delta.y = result_pos_iso.y - iso_orig_p.y; snapping_x = true; } if ( new_snapping_y ) { iso_delta.x = result_pos_iso.x - iso_orig_p.x; iso_delta.y = result_pos_iso.y - iso_orig_p.y; snapping_y = true; } if ( snapping_x && snapping_y ) { break; } } } } return iso_objects.Aggregate(Vector3.zero, (AccIn, iso_object) => { var iso_orig_p = iso_object.position; var result_pos_iso = iso_orig_p + iso_delta; if ( move ) { iso_object.position = IsoUtils.VectorBeautifier(result_pos_iso); } var pos_delta = result_pos_iso - iso_orig_p; return pos_delta.magnitude > AccIn.magnitude ? pos_delta : AccIn; }); } return iso_delta; } // --------------------------------------------------------------------- // // Gizmos // // --------------------------------------------------------------------- public static Vector3 GizmoRectangle(Vector3 center) { GizmoDotCap(new Color(1.0f, 1.0f, 1.0f, 0.3f) * Handles.zAxisColor, center, 0.15f); GizmoArrowCap(Handles.zAxisColor, center, 1.0f); return GizmoFreeMoveHandle(Handles.zAxisColor, center, 0.15f); } public static Vector3 GizmoSlider(Color color, Vector3 pos, Vector3 dir) { Handles.color = color; return Handles.Slider(pos, dir); } public static void GizmoDotCap(Color color, Vector3 center, float scale) { Handles.color = color; #if UNITY_5_6_OR_NEWER Handles.DotHandleCap( 0, center, Quaternion.identity, HandleUtility.GetHandleSize(center) * scale, EventType.Repaint); #else Handles.DotCap( 0, center, Quaternion.identity, HandleUtility.GetHandleSize(center) * scale); #endif } public static void GizmoArrowCap(Color color, Vector3 center, float scale) { Handles.color = color; #if UNITY_5_6_OR_NEWER Handles.ArrowHandleCap( 0, center, Quaternion.identity, HandleUtility.GetHandleSize(center) * scale, EventType.Repaint); #else Handles.ArrowCap( 0, center, Quaternion.identity, HandleUtility.GetHandleSize(center) * scale); #endif } public static Vector3 GizmoFreeMoveHandle(Color color, Vector3 center, float scale) { #if UNITY_5_6_OR_NEWER return Handles.FreeMoveHandle( center, Quaternion.identity, HandleUtility.GetHandleSize(center) * scale, Vector3.zero, Handles.RectangleHandleCap); #else return Handles.FreeMoveHandle( center, Quaternion.identity, HandleUtility.GetHandleSize(center) * scale, Vector3.zero, Handles.RectangleCap); #endif } // --------------------------------------------------------------------- // // Snapping // // --------------------------------------------------------------------- public static bool SnapProcess( float snap_dist, ref float min_a, float size_a, float min_b, float size_b) { var max_a = min_a + size_a; var max_b = min_b + size_b; var result = false; if ( IsSnapOverlaps(snap_dist, min_a, size_a, min_b, size_b) ) { // |min_a max_a|min_b max_b| if ( Mathf.Abs(max_a - min_b) < snap_dist ) { min_a = min_b - size_a; result = true; } // |min_b max_b|min_a max_a| if ( Mathf.Abs(max_b - min_a) < snap_dist ) { min_a = max_b; result = true; } // |min_a_____max_a| // |min_b__max_b| if ( Mathf.Abs(min_a - min_b) < snap_dist ) { min_a = min_b; result = true; } // |min_a_____max_a| // |min_b__max_b| if ( Mathf.Abs(max_a - max_b) < snap_dist ) { min_a = max_b - size_a; result = true; } } return result; } public static bool IsSnapOverlaps( float snap_dist, float min_a, float size_a, float min_b, float size_b) { return min_a + size_a + snap_dist >= min_b && min_a - snap_dist <= min_b + size_b; } public static bool IsSnapByCellsEnabled(IsoWorld iso_world) { return iso_world && (iso_world.isSnapByCells != Event.current.control); } public static bool IsSnapByObjectsEnabled(IsoWorld iso_world) { return iso_world && (iso_world.isSnapByObjects != Event.current.control); } public static bool IsSnapByObjectAllowed(IsoObject iso_object, IsoObject other_object) { var iso_object_trans = iso_object.transform; var other_object_trans = other_object.transform; while ( other_object_trans ) { if ( other_object_trans.parent == iso_object_trans ) { return false; } other_object_trans = other_object_trans.parent; } return true; } } }