mirror of
https://github.com/BlackMATov/unity-iso-tools.git
synced 2025-12-15 01:12:05 +07:00
multiple worlds support done
This commit is contained in:
@@ -7,42 +7,138 @@ namespace IsoTools.Internal {
|
||||
[CustomEditor(typeof(IsoObject)), CanEditMultipleObjects]
|
||||
class IsoObjectEditor : Editor {
|
||||
|
||||
IDictionary<IsoObject, Vector3> _positions = new Dictionary<IsoObject, Vector3>();
|
||||
IDictionary<IsoObject, float> _isoZPositions = new Dictionary<IsoObject, float>();
|
||||
IList<IsoObject> _otherObjects = new List<IsoObject>();
|
||||
Vector3 _center = Vector3.zero;
|
||||
Vector3 _viewCenter = Vector3.zero;
|
||||
Dictionary<IsoWorld, List<IsoObject>> _isoObjects = new Dictionary<IsoWorld, List<IsoObject>>();
|
||||
Dictionary<IsoWorld, List<IsoObject>> _otherObjects = new Dictionary<IsoWorld, List<IsoObject>>();
|
||||
Dictionary<IsoWorld, Vector3> _viewCenters = new Dictionary<IsoWorld, Vector3>();
|
||||
|
||||
public static readonly float SnappingDistance = 0.2f;
|
||||
// ---------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
static bool IsSnappingEnabled() {
|
||||
var iso_world = IsoWorld.Instance;
|
||||
return iso_world && (iso_world.isSnappingEnabled != Event.current.control);
|
||||
}
|
||||
|
||||
void GrabPositions() {
|
||||
var iso_world = IsoWorld.Instance;
|
||||
if ( iso_world ) {
|
||||
_positions = targets
|
||||
.OfType<IsoObject>()
|
||||
.ToDictionary(p => p, p => p.transform.position);
|
||||
_isoZPositions = targets
|
||||
.OfType<IsoObject>()
|
||||
.ToDictionary(p => p, p => p.position.z);
|
||||
_center = _viewCenter = _positions.Aggregate(Vector3.zero, (AccIn, p) => {
|
||||
return AccIn + IsoUtils.Vec3FromVec2(iso_world.IsoToScreen(p.Key.position + p.Key.size * 0.5f));
|
||||
}) / _positions.Count;
|
||||
} else {
|
||||
_positions.Clear();
|
||||
_isoZPositions.Clear();
|
||||
}
|
||||
void PrepareTargets() {
|
||||
_isoObjects = targets
|
||||
.OfType<IsoObject>()
|
||||
.Where(p => p.isoWorld)
|
||||
.GroupBy(p => p.isoWorld)
|
||||
.ToDictionary(p => p.Key, p => p.ToList());
|
||||
_viewCenters = _isoObjects.ToDictionary(
|
||||
pair => pair.Key,
|
||||
pair => {
|
||||
var iso_world = pair.Key;
|
||||
return pair.Value.Aggregate(Vector3.zero, (AccIn, p) => {
|
||||
return AccIn + IsoUtils.Vec3FromVec2(
|
||||
iso_world.IsoToScreen(p.position + p.size * 0.5f));
|
||||
}) / pair.Value.Count;
|
||||
});
|
||||
_otherObjects = FindObjectsOfType<IsoObject>()
|
||||
.Where(p => p.gameObject.activeInHierarchy && !_positions.ContainsKey(p))
|
||||
.ToList();
|
||||
.Where(p => p.IsActive() && p.isoWorld)
|
||||
.Where(p => _isoObjects.ContainsKey(p.isoWorld))
|
||||
.Where(p => !_isoObjects[p.isoWorld].Contains(p))
|
||||
.GroupBy(p => p.isoWorld)
|
||||
.ToDictionary(p => p.Key, p => p.ToList());
|
||||
}
|
||||
|
||||
void DrawCustomInspector() {
|
||||
var iso_worlds = _isoObjects.Keys.ToArray();
|
||||
IsoEditorUtils.DrawWorldProperties(iso_worlds);
|
||||
IsoEditorUtils.DrawSelfWorldProperty(iso_worlds, "IsoObject");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
void DisableCustomTools() {
|
||||
if ( Tools.hidden ) {
|
||||
Tools.hidden = false;
|
||||
Tools.current = Tool.Move;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawCustomTools() {
|
||||
if ( Tools.current == Tool.Move ) {
|
||||
Tools.hidden = true;
|
||||
ZMoveSliderTool();
|
||||
XYMoveSliderTool(Handles.xAxisColor, IsoUtils.vec3OneX);
|
||||
XYMoveSliderTool(Handles.yAxisColor, IsoUtils.vec3OneY);
|
||||
XYMoveRectangleTool();
|
||||
} else {
|
||||
Tools.hidden = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ZMoveSliderTool() {
|
||||
foreach ( var iso_world in _viewCenters.Keys.ToList() ) {
|
||||
EditorGUI.BeginChangeCheck();
|
||||
var old_center = _viewCenters[iso_world];
|
||||
var new_center = IsoEditorUtils.GizmoSlider(
|
||||
Handles.zAxisColor,
|
||||
old_center,
|
||||
IsoUtils.vec3OneY);
|
||||
if ( EditorGUI.EndChangeCheck() ) {
|
||||
var old_delta = new_center - old_center;
|
||||
var new_delta = IsoEditorUtils.ZMoveIsoObjects(
|
||||
true,
|
||||
iso_world,
|
||||
_isoObjects,
|
||||
_otherObjects,
|
||||
old_delta.y / iso_world.tileHeight) * iso_world.tileHeight;
|
||||
_viewCenters[iso_world] = old_center + IsoUtils.Vec3FromY(new_delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void XYMoveSliderTool(Color color, Vector3 dir) {
|
||||
foreach ( var iso_world in _viewCenters.Keys.ToList() ) {
|
||||
EditorGUI.BeginChangeCheck();
|
||||
var old_center = _viewCenters[iso_world];
|
||||
var new_center = IsoEditorUtils.GizmoSlider(
|
||||
color,
|
||||
old_center,
|
||||
iso_world.IsoToScreen(dir));
|
||||
if ( EditorGUI.EndChangeCheck() ) {
|
||||
var old_delta = new_center - old_center;
|
||||
var new_delta = iso_world.IsoToScreen(IsoEditorUtils.XYMoveIsoObjects(
|
||||
true,
|
||||
iso_world,
|
||||
_isoObjects,
|
||||
_otherObjects,
|
||||
iso_world.ScreenToIso(old_delta)));
|
||||
_viewCenters[iso_world] = old_center + IsoUtils.Vec3FromVec2(new_delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void XYMoveRectangleTool() {
|
||||
foreach ( var iso_world in _viewCenters.Keys.ToList() ) {
|
||||
EditorGUI.BeginChangeCheck();
|
||||
var old_center = _viewCenters[iso_world];
|
||||
var new_center = IsoEditorUtils.GizmoRectangle(old_center);
|
||||
if ( EditorGUI.EndChangeCheck() ) {
|
||||
var old_delta = new_center - old_center;
|
||||
var new_delta = iso_world.IsoToScreen(IsoEditorUtils.XYMoveIsoObjects(
|
||||
true,
|
||||
iso_world,
|
||||
_isoObjects,
|
||||
_otherObjects,
|
||||
iso_world.ScreenToIso(old_delta)));
|
||||
_viewCenters[iso_world] = old_center + IsoUtils.Vec3FromVec2(new_delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
void DirtyTargetPosition() {
|
||||
if ( targets.Length == 1 && (target is IsoObject) && (target as IsoObject).gameObject.activeInHierarchy ) {
|
||||
if ( targets.Length == 1 && (target is IsoObject) && (target as IsoObject).IsActive() ) {
|
||||
var position_prop = serializedObject.FindProperty("_position");
|
||||
if ( position_prop != null ) {
|
||||
var last_value = position_prop.vector3Value;
|
||||
@@ -56,311 +152,29 @@ namespace IsoTools.Internal {
|
||||
}
|
||||
}
|
||||
|
||||
void DrawWorldEditorProperties() {
|
||||
var iso_world = IsoWorld.Instance;
|
||||
if ( iso_world ) {
|
||||
var so = new SerializedObject(iso_world);
|
||||
EditorGUILayout.PropertyField(so.FindProperty("_showIsoBounds"));
|
||||
EditorGUILayout.PropertyField(so.FindProperty("_showScreenBounds"));
|
||||
EditorGUILayout.PropertyField(so.FindProperty("_showDepends"));
|
||||
EditorGUILayout.PropertyField(so.FindProperty("_snappingEnabled"));
|
||||
if ( GUI.changed ) {
|
||||
so.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawSelfInfoProperties() {
|
||||
var iso_objects = targets.OfType<IsoObject>();
|
||||
if ( iso_objects.Count() > 0 ) {
|
||||
var mixed_world = iso_objects.GroupBy(p => p.isoWorld).Count() > 1;
|
||||
IsoEditorUtils.DoWithEnabledGUI(false, () => {
|
||||
IsoEditorUtils.DoWithMixedValue(mixed_world, () => {
|
||||
EditorGUILayout.ObjectField("Current Object World", iso_objects.First().isoWorld, typeof(IsoWorld), true);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static bool SnappingProcess(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 ( IsSnappingIntersect(min_a, size_a, min_b, size_b) ) {
|
||||
// |min_a max_a|min_b max_b|
|
||||
if ( Mathf.Abs(max_a - min_b) < SnappingDistance ) {
|
||||
min_a = min_b - size_a;
|
||||
result = true;
|
||||
}
|
||||
// |min_b max_b|min_a max_a|
|
||||
if ( Mathf.Abs(max_b - min_a) < SnappingDistance ) {
|
||||
min_a = max_b;
|
||||
result = true;
|
||||
}
|
||||
// |min_a_____max_a|
|
||||
// |min_b__max_b|
|
||||
if ( Mathf.Abs(min_a - min_b) < SnappingDistance ) {
|
||||
min_a = min_b;
|
||||
result = true;
|
||||
}
|
||||
// |min_a_____max_a|
|
||||
// |min_b__max_b|
|
||||
if ( Mathf.Abs(max_a - max_b) < SnappingDistance ) {
|
||||
min_a = max_b - size_a;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool IsSnappingIntersect(float min_a, float size_a, float min_b, float size_b) {
|
||||
return
|
||||
min_a + size_a + SnappingDistance >= min_b &&
|
||||
min_a - SnappingDistance <= min_b + size_b;
|
||||
}
|
||||
|
||||
public static float ZMoveIsoObjects(
|
||||
bool move,
|
||||
float delta,
|
||||
IDictionary<IsoObject, float> iso_z_positions,
|
||||
IList<IsoObject> other_objects)
|
||||
{
|
||||
if ( move ) {
|
||||
Undo.RecordObjects(
|
||||
iso_z_positions.Keys.ToArray(),
|
||||
iso_z_positions.Count > 1 ? "Move IsoObjects" : "Move IsoObject");
|
||||
}
|
||||
if ( IsSnappingEnabled() ) {
|
||||
var snapping_z = false;
|
||||
foreach ( var pair in iso_z_positions ) {
|
||||
var iso_object = pair.Key;
|
||||
var iso_orig_z = pair.Value;
|
||||
var result_p_z = iso_orig_z + delta;
|
||||
foreach ( var other in other_objects ) {
|
||||
if ( IsSnappingIntersect(iso_object.positionX, iso_object.sizeX, other.positionX, other.sizeX) &&
|
||||
IsSnappingIntersect(iso_object.positionY, iso_object.sizeY, other.positionY, other.sizeY) )
|
||||
{
|
||||
var new_snapping_z = !snapping_z && IsSnappingIntersect(result_p_z, iso_object.sizeZ, other.positionZ, other.sizeZ)
|
||||
? SnappingProcess(ref result_p_z, iso_object.sizeZ, other.positionZ, other.sizeZ)
|
||||
: false;
|
||||
if ( new_snapping_z ) {
|
||||
delta = result_p_z - iso_orig_z;
|
||||
snapping_z = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( snapping_z ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !snapping_z ) {
|
||||
var pair = iso_z_positions.First();
|
||||
var iso_object = pair.Key;
|
||||
var iso_orig_z = pair.Value;
|
||||
var result_p_z = iso_orig_z + delta;
|
||||
var new_snapping_z = SnappingProcess(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
return iso_z_positions.Aggregate(0.0f, (AccIn, pair) => {
|
||||
var iso_object = pair.Key;
|
||||
var iso_orig_z = pair.Value;
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
public static Vector3 XYMoveIsoObjects(
|
||||
bool move,
|
||||
Vector3 delta,
|
||||
IDictionary<IsoObject, Vector3> positions,
|
||||
IList<IsoObject> other_objects)
|
||||
{
|
||||
if ( move ) {
|
||||
Undo.RecordObjects(
|
||||
positions.Keys.ToArray(),
|
||||
positions.Count > 1 ? "Move IsoObjects" : "Move IsoObject");
|
||||
}
|
||||
if ( IsSnappingEnabled() ) {
|
||||
var snapping_x = false;
|
||||
var snapping_y = false;
|
||||
foreach ( var pair in positions ) {
|
||||
var iso_object = pair.Key;
|
||||
var iso_orig_p = pair.Value;
|
||||
var result_pos = iso_orig_p + delta;
|
||||
var result_pos_iso = IsoWorld.Instance.ScreenToIso(result_pos, iso_object.positionZ);
|
||||
foreach ( var other in other_objects ) {
|
||||
if ( IsSnappingIntersect(iso_object.positionZ, iso_object.sizeZ, other.positionZ, other.sizeZ) ) {
|
||||
var new_snapping_x = !snapping_x && IsSnappingIntersect(result_pos_iso.y, iso_object.sizeY, other.positionY, other.sizeY)
|
||||
? SnappingProcess(ref result_pos_iso.x, iso_object.sizeX, other.positionX, other.sizeX)
|
||||
: false;
|
||||
var new_snapping_y = !snapping_y && IsSnappingIntersect(result_pos_iso.x, iso_object.sizeX, other.positionX, other.sizeX)
|
||||
? SnappingProcess(ref result_pos_iso.y, iso_object.sizeY, other.positionY, other.sizeY)
|
||||
: false;
|
||||
if ( new_snapping_x || new_snapping_y ) {
|
||||
result_pos = IsoWorld.Instance.IsoToScreen(result_pos_iso);
|
||||
if ( new_snapping_x ) {
|
||||
delta.x = result_pos.x - iso_orig_p.x;
|
||||
delta.y = result_pos.y - iso_orig_p.y;
|
||||
snapping_x = true;
|
||||
}
|
||||
if ( new_snapping_y ) {
|
||||
delta.x = result_pos.x - iso_orig_p.x;
|
||||
delta.y = result_pos.y - iso_orig_p.y;
|
||||
snapping_y = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( snapping_x && snapping_y ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !snapping_x && !snapping_y ) {
|
||||
var pair = positions.First();
|
||||
var iso_object = pair.Key;
|
||||
var iso_orig_p = pair.Value;
|
||||
var result_pos = iso_orig_p + delta;
|
||||
var result_pos_iso = IsoWorld.Instance.ScreenToIso(result_pos, iso_object.positionZ);
|
||||
var new_snapping_x = SnappingProcess(ref result_pos_iso.x, iso_object.sizeX, iso_object.tilePositionX, 1.0f);
|
||||
var new_snapping_y = SnappingProcess(ref result_pos_iso.y, iso_object.sizeY, iso_object.tilePositionY, 1.0f);
|
||||
if ( new_snapping_x || new_snapping_y ) {
|
||||
result_pos = IsoWorld.Instance.IsoToScreen(result_pos_iso);
|
||||
if ( new_snapping_x ) {
|
||||
delta.x = result_pos.x - iso_orig_p.x;
|
||||
delta.y = result_pos.y - iso_orig_p.y;
|
||||
snapping_x = true;
|
||||
}
|
||||
if ( new_snapping_y ) {
|
||||
delta.x = result_pos.x - iso_orig_p.x;
|
||||
delta.y = result_pos.y - iso_orig_p.y;
|
||||
snapping_y = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return positions.Aggregate(Vector3.zero, (AccIn, pair) => {
|
||||
var iso_object = pair.Key;
|
||||
var iso_orig_p = pair.Value;
|
||||
var result_pos = iso_orig_p + delta;
|
||||
if ( move ) {
|
||||
var new_iso_pos = IsoWorld.Instance.ScreenToIso(
|
||||
result_pos,
|
||||
iso_object.positionZ);
|
||||
iso_object.position = IsoUtils.VectorBeautifier(new_iso_pos);
|
||||
}
|
||||
var pos_delta = result_pos - iso_orig_p;
|
||||
return pos_delta.magnitude > AccIn.magnitude ? pos_delta : AccIn;
|
||||
});
|
||||
}
|
||||
|
||||
void ZMoveSlider() {
|
||||
var iso_world = IsoWorld.Instance;
|
||||
if ( iso_world ) {
|
||||
Handles.color = Handles.zAxisColor;
|
||||
var delta = Handles.Slider(_viewCenter, IsoUtils.vec3OneY) - _viewCenter;
|
||||
if ( Mathf.Abs(delta.y) > Mathf.Epsilon ) {
|
||||
float tmp_y = ZMoveIsoObjects(
|
||||
true,
|
||||
(_viewCenter.y - _center.y + delta.y) / iso_world.tileHeight,
|
||||
_isoZPositions,
|
||||
_otherObjects);
|
||||
_viewCenter = _center + IsoUtils.Vec3FromY(tmp_y * iso_world.tileHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void XYMoveSlider(Color color, Vector3 dir) {
|
||||
var iso_world = IsoWorld.Instance;
|
||||
if ( iso_world ) {
|
||||
Handles.color = color;
|
||||
var delta = Handles.Slider(_viewCenter, iso_world.IsoToScreen(dir)) - _viewCenter;
|
||||
if ( delta.magnitude > Mathf.Epsilon ) {
|
||||
_viewCenter = _center + XYMoveIsoObjects(
|
||||
true,
|
||||
_viewCenter - _center + delta,
|
||||
_positions,
|
||||
_otherObjects);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void XYMoveRectangle() {
|
||||
var iso_world = IsoWorld.Instance;
|
||||
if ( iso_world ) {
|
||||
Handles.color = new Color(
|
||||
Handles.zAxisColor.r,
|
||||
Handles.zAxisColor.g,
|
||||
Handles.zAxisColor.b,
|
||||
0.3f);
|
||||
Handles.DotCap(
|
||||
0,
|
||||
_viewCenter,
|
||||
Quaternion.identity,
|
||||
HandleUtility.GetHandleSize(_viewCenter) * 0.15f);
|
||||
Handles.color = Handles.zAxisColor;
|
||||
Handles.ArrowCap(
|
||||
0,
|
||||
_viewCenter,
|
||||
Quaternion.identity,
|
||||
HandleUtility.GetHandleSize(_viewCenter));
|
||||
Handles.color = Handles.zAxisColor;
|
||||
var delta = Handles.FreeMoveHandle(
|
||||
_viewCenter,
|
||||
Quaternion.identity,
|
||||
HandleUtility.GetHandleSize(_viewCenter) * 0.15f,
|
||||
Vector3.zero,
|
||||
Handles.RectangleCap) - _viewCenter;
|
||||
if ( delta.magnitude > Mathf.Epsilon ) {
|
||||
_viewCenter = _center + XYMoveIsoObjects(
|
||||
true,
|
||||
_viewCenter - _center + delta,
|
||||
_positions,
|
||||
_otherObjects);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// ---------------------------------------------------------------------
|
||||
//
|
||||
// Messages
|
||||
//
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
void OnEnable() {
|
||||
GrabPositions();
|
||||
PrepareTargets();
|
||||
}
|
||||
|
||||
void OnDisable() {
|
||||
if ( Tools.hidden ) {
|
||||
Tools.hidden = false;
|
||||
Tools.current = Tool.Move;
|
||||
}
|
||||
DisableCustomTools();
|
||||
}
|
||||
|
||||
void OnSceneGUI() {
|
||||
if ( Tools.current == Tool.Move ) {
|
||||
Tools.hidden = true;
|
||||
ZMoveSlider();
|
||||
XYMoveSlider(Handles.xAxisColor, IsoUtils.vec3OneX);
|
||||
XYMoveSlider(Handles.yAxisColor, IsoUtils.vec3OneY);
|
||||
XYMoveRectangle();
|
||||
} else {
|
||||
Tools.hidden = false;
|
||||
}
|
||||
DrawCustomTools();
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI() {
|
||||
DrawDefaultInspector();
|
||||
GrabPositions();
|
||||
PrepareTargets();
|
||||
DirtyTargetPosition();
|
||||
DrawWorldEditorProperties();
|
||||
DrawSelfInfoProperties();
|
||||
DrawDefaultInspector();
|
||||
DrawCustomInspector();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user