From f6f6213de61536d79ec3133eaba224396e9a04b9 Mon Sep 17 00:00:00 2001 From: Banane_Rotative Date: Sat, 17 Jan 2026 19:35:45 +0100 Subject: [PATCH 1/2] Add: anchored objects Anchored objects can be connected together by calling a method. --- Assets/Scripts/Anchor.meta | 8 ++ Assets/Scripts/Anchor/Anchor.cs | 63 ++++++++++ Assets/Scripts/Anchor/Anchor.cs.meta | 2 + Assets/Scripts/Anchor/AnchoredObject.cs | 120 +++++++++++++++++++ Assets/Scripts/Anchor/AnchoredObject.cs.meta | 2 + 5 files changed, 195 insertions(+) create mode 100644 Assets/Scripts/Anchor.meta create mode 100644 Assets/Scripts/Anchor/Anchor.cs create mode 100644 Assets/Scripts/Anchor/Anchor.cs.meta create mode 100644 Assets/Scripts/Anchor/AnchoredObject.cs create mode 100644 Assets/Scripts/Anchor/AnchoredObject.cs.meta diff --git a/Assets/Scripts/Anchor.meta b/Assets/Scripts/Anchor.meta new file mode 100644 index 0000000..13cb4bc --- /dev/null +++ b/Assets/Scripts/Anchor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 60cc4243135e5cd4b9d21f837db97b31 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Anchor/Anchor.cs b/Assets/Scripts/Anchor/Anchor.cs new file mode 100644 index 0000000..14b8687 --- /dev/null +++ b/Assets/Scripts/Anchor/Anchor.cs @@ -0,0 +1,63 @@ +using UnityEngine; +#if UNITY_EDITOR +using UnityEditor; +#endif + +public class Anchor : MonoBehaviour +{ + // Comparison tolerances + const float positionEPS = 0.1f; + const float rotationEPS = 0.1f; + + // See anchor within editor + #if UNITY_EDITOR + public const float tipsSize = 0.2f; + + private void OnDrawGizmosSelected() + { + Handles.color = Color.magenta; + Vector3 position = transform.position; + float size = transform.lossyScale.x; + + if (size >= 0) + { + Handles.ArrowHandleCap( + 0, + position, + Quaternion.LookRotation(transform.forward), + size, + EventType.Repaint + ); + + Vector3 leftLimit = position - size*transform.right; + Vector3 rightLimit = position + size*transform.right; + Handles.DrawLine(leftLimit, rightLimit); + + Handles.DrawLine( + leftLimit - tipsSize*size*transform.forward, + leftLimit + tipsSize*size*transform.forward + ); + Handles.DrawLine( + rightLimit - tipsSize*size*transform.forward, + rightLimit + tipsSize*size*transform.forward + ); + } + } + #endif + + /// + /// Test whether this anchor is connected to another anchor + /// + /// The other anchor to compare to + /// Whether to test for scale match + /// The anchoring state of this anchor and the given anchor + public bool IsAnchoredTo(Anchor other, bool matchScales=true) + { + if (matchScales && (Mathf.Abs(transform.lossyScale.x - other.transform.lossyScale.x) > positionEPS)) + { + return false; + } + return Quaternion.Angle(transform.rotation*Quaternion.AngleAxis(180f, Vector3.up), other.transform.rotation) < rotationEPS + && Vector3.Distance(transform.position, other.transform.position) < positionEPS; + } +} diff --git a/Assets/Scripts/Anchor/Anchor.cs.meta b/Assets/Scripts/Anchor/Anchor.cs.meta new file mode 100644 index 0000000..670587e --- /dev/null +++ b/Assets/Scripts/Anchor/Anchor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c8e92a0688e18aa4891eb7937ca9cd0e \ No newline at end of file diff --git a/Assets/Scripts/Anchor/AnchoredObject.cs b/Assets/Scripts/Anchor/AnchoredObject.cs new file mode 100644 index 0000000..decbef7 --- /dev/null +++ b/Assets/Scripts/Anchor/AnchoredObject.cs @@ -0,0 +1,120 @@ +using System.Collections.Generic; +using UnityEngine; + +public class AnchoredObject : MonoBehaviour +{ + [SerializeField] List anchors = new List(); + + /// + /// Get an anchor from its ID (index) + /// + /// ID of the anchor to search for + /// The anchor that has the given ID + public Anchor GetAnchorFromID(int anchorID) + { + if (anchorID > anchors.Count) + { + Debug.LogError("Error: Tried to anchor to an inexisting anchor. Check anchors list."); + } + return anchors[anchorID]; + } + + /// + /// Anchor this object to another + /// + /// The anchored object to connect to + /// ID of the partner anchor to connect to + /// ID of anchor this object wants to connect + /// Whether to anchor scales too + public void AnchorTo(AnchoredObject partner, int partnerAnchorID, int myAnchorID, bool matchScales=true) + { + AnchorTo( + GetAnchorFromID(myAnchorID), + partner.GetAnchorFromID(partnerAnchorID) + ); + } + + /// + /// Anchor this object to another + /// + /// The anchor to connect + /// The anchor of the other object to connect to + /// Whether to anchor scales too + public void AnchorTo(Anchor myAnchor, Anchor partnerAnchor, bool matchScales=true) + { + if (matchScales) + { + // Match scales + float sizeDelta = partnerAnchor.transform.lossyScale.x / myAnchor.transform.lossyScale.x; + transform.localScale *= sizeDelta; + } + + // Match rotations + transform.rotation = + partnerAnchor.transform.rotation + * Quaternion.AngleAxis(180f, Vector3.up) + * Quaternion.Inverse(myAnchor.transform.rotation) + * transform.rotation; + + // Match positions + transform.position += partnerAnchor.transform.position - myAnchor.transform.position; + } + + /// + /// Connect multiple anchors of this object with multiple anchors. + /// If one of the connections fails, the anchoring operation fails. + /// + /// The anchored object to connect to + /// IDs of the partner anchors to connect to + /// IDs of the anchors this object wants to connect + /// Whether to anchor scales too + /// Whether the anchoring succeeded or not + public bool AnchorToMultiple(AnchoredObject partner, IList partnerAnchorIDs, IList myAnchorIDs, bool matchScales=true) + { + if (myAnchorIDs.Count != partnerAnchorIDs.Count) + { + Debug.LogError("Error: Number of anchors must match."); + } + List myAnchors = new List(); + List partnerAnchors = new List(); + for (int i = 0; i < myAnchorIDs.Count; i++) + { + myAnchors.Add(GetAnchorFromID(myAnchorIDs[i])); + partnerAnchors.Add(partner.GetAnchorFromID(partnerAnchorIDs[i])); + } + return AnchorToMultiple(myAnchors, partnerAnchors, matchScales); + } + + /// + /// Connect multiple anchors of this object with multiple anchors. + /// If one of the connections fails, the anchoring operation fails. + /// + /// The anchors this object wants to connect + /// The anchors this object wants to connect to + /// Whether to anchor scales too + /// Whether the anchoring succeeded or not + public bool AnchorToMultiple(IList myAnchors, IList targetAnchors, bool matchScales=true) + { + if (myAnchors.Count != targetAnchors.Count) + { + Debug.LogError("Error: Number of anchors must match."); + return false; + } + if (myAnchors.Count == 0) + { + Debug.LogError("Amount of anchors to connect must be at least 1."); + return false; + } + + // Connect the first anchors. Then, test if other anchors match. + AnchorTo(myAnchors[0], targetAnchors[0], matchScales); + for (int i=1; i Date: Sat, 17 Jan 2026 20:33:47 +0100 Subject: [PATCH 2/2] Add: Anchor connect button in Editor The button can be accessed in the Inspector when an object is selected --- Assets/Scripts/Editor.meta | 8 ++++ Assets/Scripts/Editor/AnchoredObjectEditor.cs | 41 +++++++++++++++++++ .../Editor/AnchoredObjectEditor.cs.meta | 2 + 3 files changed, 51 insertions(+) create mode 100644 Assets/Scripts/Editor.meta create mode 100644 Assets/Scripts/Editor/AnchoredObjectEditor.cs create mode 100644 Assets/Scripts/Editor/AnchoredObjectEditor.cs.meta diff --git a/Assets/Scripts/Editor.meta b/Assets/Scripts/Editor.meta new file mode 100644 index 0000000..693a207 --- /dev/null +++ b/Assets/Scripts/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 961ab1cb357b32f4e96861e3f4e1dd36 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Editor/AnchoredObjectEditor.cs b/Assets/Scripts/Editor/AnchoredObjectEditor.cs new file mode 100644 index 0000000..35ccac3 --- /dev/null +++ b/Assets/Scripts/Editor/AnchoredObjectEditor.cs @@ -0,0 +1,41 @@ +using UnityEngine; +#if UNITY_EDITOR +using UnityEditor; + +[CustomEditor(typeof(AnchoredObject))] +public class AnchoredObjectEditor : Editor +{ + [Header("Connect via editor")] + Anchor myAnchor; + Anchor partnerAnchor; + bool matchScales = true; + + public override void OnInspectorGUI() + { + DrawDefaultInspector(); + + EditorGUILayout.Space(); + EditorGUILayout.LabelField("", GUI.skin.horizontalSlider); + EditorGUILayout.LabelField("Connect the anchors directly via the editor", EditorStyles.boldLabel); + EditorGUILayout.Space(); + + myAnchor = (Anchor) EditorGUILayout.ObjectField("My Anchor", myAnchor, typeof(Anchor), true); + partnerAnchor = (Anchor) EditorGUILayout.ObjectField("Partner Anchor", partnerAnchor, typeof(Anchor), true); + matchScales = EditorGUILayout.Toggle("Match Scales?", matchScales); + + AnchoredObject obj = (AnchoredObject)target; + + if (GUILayout.Button("Connect anchors")) + { + if (!myAnchor || !partnerAnchor) + { + Debug.LogWarning("Anchors not assigned", this); + return; + } + obj.AnchorTo(myAnchor, partnerAnchor, matchScales); + } + } +} + + +#endif \ No newline at end of file diff --git a/Assets/Scripts/Editor/AnchoredObjectEditor.cs.meta b/Assets/Scripts/Editor/AnchoredObjectEditor.cs.meta new file mode 100644 index 0000000..72c9289 --- /dev/null +++ b/Assets/Scripts/Editor/AnchoredObjectEditor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 28dbead944bac384f8bd3e8a1975b1d5 \ No newline at end of file