Add: anchored objects

Anchored objects can be connected together by calling a method.
This commit is contained in:
Banane_Rotative
2026-01-17 19:35:45 +01:00
parent 65af11d0cf
commit f6f6213de6
5 changed files with 195 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 60cc4243135e5cd4b9d21f837db97b31
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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
/// <summary>
/// Test whether this anchor is connected to another anchor
/// </summary>
/// <param name="other">The other anchor to compare to</param>
/// <param name="matchScales">Whether to test for scale match</param>
/// <returns>The anchoring state of this anchor and the given anchor</returns>
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;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c8e92a0688e18aa4891eb7937ca9cd0e

View File

@@ -0,0 +1,120 @@
using System.Collections.Generic;
using UnityEngine;
public class AnchoredObject : MonoBehaviour
{
[SerializeField] List<Anchor> anchors = new List<Anchor>();
/// <summary>
/// Get an anchor from its ID (index)
/// </summary>
/// <param name="anchorID">ID of the anchor to search for</param>
/// <returns>The anchor that has the given ID</returns>
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];
}
/// <summary>
/// Anchor this object to another
/// </summary>
/// <param name="partner">The anchored object to connect to</param>
/// <param name="partnerAnchorID">ID of the partner anchor to connect to</param>
/// <param name="myAnchorID">ID of anchor this object wants to connect</param>
/// <param name="matchScales">Whether to anchor scales too</param>
public void AnchorTo(AnchoredObject partner, int partnerAnchorID, int myAnchorID, bool matchScales=true)
{
AnchorTo(
GetAnchorFromID(myAnchorID),
partner.GetAnchorFromID(partnerAnchorID)
);
}
/// <summary>
/// Anchor this object to another
/// </summary>
/// <param name="myAnchor">The anchor to connect</param>
/// <param name="partnerAnchor">The anchor of the other object to connect to</param>
/// <param name="matchScales">Whether to anchor scales too</param>
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;
}
/// <summary>
/// Connect multiple anchors of this object with multiple anchors.
/// If one of the connections fails, the anchoring operation fails.
/// </summary>
/// <param name="partner">The anchored object to connect to</param>
/// <param name="partnerAnchorIDs">IDs of the partner anchors to connect to</param>
/// <param name="myAnchorIDs">IDs of the anchors this object wants to connect</param>
/// <param name="matchScales">Whether to anchor scales too</param>
/// <returns>Whether the anchoring succeeded or not</returns>
public bool AnchorToMultiple(AnchoredObject partner, IList<int> partnerAnchorIDs, IList<int> myAnchorIDs, bool matchScales=true)
{
if (myAnchorIDs.Count != partnerAnchorIDs.Count)
{
Debug.LogError("Error: Number of anchors must match.");
}
List<Anchor> myAnchors = new List<Anchor>();
List<Anchor> partnerAnchors = new List<Anchor>();
for (int i = 0; i < myAnchorIDs.Count; i++)
{
myAnchors.Add(GetAnchorFromID(myAnchorIDs[i]));
partnerAnchors.Add(partner.GetAnchorFromID(partnerAnchorIDs[i]));
}
return AnchorToMultiple(myAnchors, partnerAnchors, matchScales);
}
/// <summary>
/// Connect multiple anchors of this object with multiple anchors.
/// If one of the connections fails, the anchoring operation fails.
/// </summary>
/// <param name="myAnchors">The anchors this object wants to connect</param>
/// <param name="targetAnchors">The anchors this object wants to connect to</param>
/// <param name="matchScales">Whether to anchor scales too</param>
/// <returns>Whether the anchoring succeeded or not</returns>
public bool AnchorToMultiple(IList<Anchor> myAnchors, IList<Anchor> 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<myAnchors.Count; i++)
{
if (! myAnchors[i].IsAnchoredTo(targetAnchors[i], matchScales))
{
return false;
}
}
return true;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a7e5718d381203c488586d59acd4a86d