Initial commit
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Handles socket proximity detection, highlighting, and closest-socket tracking.
|
||||
///
|
||||
/// Key fixes vs previous version:
|
||||
/// 1. Searches from col.transform.ROOT — so if OverlapSphere hits a child mesh
|
||||
/// collider, we still find SocketPoints that are siblings of that mesh.
|
||||
/// 2. Uses QueryTriggerInteraction.Collide — socket colliders are usually triggers;
|
||||
/// without this flag the overlap silently finds nothing when
|
||||
/// Physics.queriesHitTriggers is false in Project Settings.
|
||||
/// 3. Deduplicates across colliders that share a root, so a multi-collider block
|
||||
/// doesn't add its sockets multiple times.
|
||||
/// </summary>
|
||||
public class SnapSystem : MonoBehaviour
|
||||
{
|
||||
private static SnapSystem instance;
|
||||
public static SnapSystem getInstance() => instance;
|
||||
|
||||
[SerializeField] private float socketDetectionRadius = 0.5f;
|
||||
|
||||
private readonly List<SocketPoint> nearbySockets = new List<SocketPoint>();
|
||||
private readonly HashSet<Transform> visitedRoots = new HashSet<Transform>();
|
||||
private SocketPoint closestSocket;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (instance == null) instance = this;
|
||||
else Destroy(gameObject);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Public API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Re-scans for sockets around <paramref name="detectionPoint"/>.
|
||||
/// Call every frame while a ghost is being dragged.
|
||||
/// </summary>
|
||||
/// <param name="detectionPoint">
|
||||
/// World-space ray hit point on the world surface — NOT the ghost's own position.
|
||||
/// </param>
|
||||
/// <param name="ghostRoot">
|
||||
/// The ghost's root transform. Sockets belonging to this hierarchy are ignored.
|
||||
/// </param>
|
||||
public void UpdateSockets(Vector3 detectionPoint, Transform ghostRoot)
|
||||
{
|
||||
ClearHighlights();
|
||||
nearbySockets.Clear();
|
||||
visitedRoots.Clear();
|
||||
closestSocket = null;
|
||||
|
||||
// QueryTriggerInteraction.Collide ensures trigger colliders (typical for sockets) are found
|
||||
Collider[] colliders = Physics.OverlapSphere(detectionPoint, socketDetectionRadius,
|
||||
Physics.AllLayers, QueryTriggerInteraction.Collide);
|
||||
|
||||
foreach (Collider col in colliders)
|
||||
{
|
||||
Transform root = col.transform.root;
|
||||
|
||||
// Skip anything that belongs to the held ghost
|
||||
if (ghostRoot != null && root == ghostRoot) continue;
|
||||
|
||||
// Don't process the same block twice (it may have multiple colliders)
|
||||
if (visitedRoots.Contains(root)) continue;
|
||||
visitedRoots.Add(root);
|
||||
|
||||
// Search from root so we find ALL SocketPoints on the block,
|
||||
// regardless of which child collider was hit by the overlap.
|
||||
foreach (SocketPoint socket in root.GetComponentsInChildren<SocketPoint>())
|
||||
{
|
||||
if (socket.IsOccupied()) continue;
|
||||
|
||||
nearbySockets.Add(socket);
|
||||
socket.Highlight(HighlightState.Compatible);
|
||||
|
||||
Debug.Log($"[SnappingSystem] Found socket: {socket.name} on {root.name}");
|
||||
}
|
||||
}
|
||||
|
||||
if (nearbySockets.Count > 0)
|
||||
{
|
||||
closestSocket = FindClosest(detectionPoint, nearbySockets);
|
||||
closestSocket?.Highlight(HighlightState.Active);
|
||||
Debug.Log($"[SnappingSystem] Closest socket: {closestSocket?.name}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Resets all highlight states without clearing the list.</summary>
|
||||
public void ClearHighlights()
|
||||
{
|
||||
foreach (SocketPoint socket in nearbySockets)
|
||||
if (socket != null)
|
||||
socket.Highlight(HighlightState.Default);
|
||||
}
|
||||
|
||||
/// <summary>Full reset — clears highlights and all cached data.</summary>
|
||||
public void Clear()
|
||||
{
|
||||
ClearHighlights();
|
||||
nearbySockets.Clear();
|
||||
visitedRoots.Clear();
|
||||
closestSocket = null;
|
||||
}
|
||||
|
||||
public List<SocketPoint> GetNearbySockets() => nearbySockets;
|
||||
public SocketPoint GetClosestSocket() => closestSocket;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Private helpers
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private static SocketPoint FindClosest(Vector3 position, List<SocketPoint> sockets)
|
||||
{
|
||||
SocketPoint closest = null;
|
||||
float minDist = float.MaxValue;
|
||||
|
||||
foreach (SocketPoint socket in sockets)
|
||||
{
|
||||
float dist = Vector3.Distance(position, socket.GetTransform().position);
|
||||
if (dist < minDist)
|
||||
{
|
||||
minDist = dist;
|
||||
closest = socket;
|
||||
}
|
||||
}
|
||||
return closest;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user