using UnityEngine; /// /// regulare snap performed in free move /// public class DefaultSnapBehavior : ISnapBehavior { public bool TrySnap(BlockEditContext ctx) { if (ctx.TargetSocket == null) return false; if (ctx.MySocket != null && !ctx.TargetSocket.CanAccept(ctx.MySocket)) return false; if (ctx.MySocket != null) { // 1. Primary Alignment: Align the exact socket normals Vector3 myNormal = ctx.MySocket.GetNormal().normalized; Vector3 targetNormal = -ctx.TargetSocket.GetNormal().normalized; Quaternion primaryRot = Quaternion.FromToRotation(myNormal, targetNormal); ctx.GhostTransform.rotation = primaryRot * ctx.GhostTransform.rotation; // 2. Secondary Alignment: Align the 'Up' (or Forward) vectors to prevent random twisting/rolling Vector3 mySecondary = Mathf.Abs(Vector3.Dot(ctx.MySocket.transform.up, targetNormal)) < 0.9f ? ctx.MySocket.transform.up : ctx.MySocket.transform.forward; Vector3 targetSecondary = Mathf.Abs(Vector3.Dot(ctx.TargetSocket.transform.up, -targetNormal)) < 0.9f ? ctx.TargetSocket.transform.up : ctx.TargetSocket.transform.forward; // Project secondary vectors onto the flat plane between the sockets Vector3 projectedMySecondary = Vector3.ProjectOnPlane(mySecondary, targetNormal).normalized; Vector3 projectedTargetSecondary = Vector3.ProjectOnPlane(targetSecondary, targetNormal).normalized; if (projectedMySecondary != Vector3.zero && projectedTargetSecondary != Vector3.zero) { // Find the twist angle needed to align the secondary axes float angle = Vector3.SignedAngle(projectedMySecondary, projectedTargetSecondary, targetNormal); // Snap to the nearest 45 degrees to allow manual 'R' rotations to persist! float correction = angle - Mathf.Round(angle / 45f) * 45f; // Rotate the ghost around its own pivot (since we haven't translated yet) ctx.GhostTransform.rotation = Quaternion.AngleAxis(correction, targetNormal) * ctx.GhostTransform.rotation; } // 3. Translate the ghost so the sockets physically touch ctx.GhostTransform.position += ctx.TargetSocket.transform.position - ctx.MySocket.transform.position; } else { Transform pivot = ctx.AttachPoint != null ? ctx.AttachPoint : ctx.GhostTransform; Vector3 pivotOffset = pivot.position - ctx.GhostTransform.position; ctx.GhostTransform.position = ctx.TargetSocket.transform.position - pivotOffset; } return true; } }