using UnityEngine; using UnityEngine.XR.Interaction.Toolkit.Interactables; // XR Toolkit用 public enum BlockColor { Red, Blue, Green } public enum BlockShapeType { TShape, CShape } // ト字, コ字 public class PuzzleBlock : MonoBehaviour { [field: SerializeField] public BlockColor Color { get; private set; } [field: SerializeField] public BlockShapeType ShapeType { get; private set; } [Header("スナップ(合体)位置の設定")] [Tooltip("相手と合体する基準位置(空のGameObject)を指定。未設定でも中心位置でスナップします")] [SerializeField] private Transform snapPoint; private PuzzleBlock nearbyPartner; // 近くにある結合対象のブロック private bool isConnected = false; // 結合済みフラグ // リセット用の初期座標・回転保持用 private Vector3 initialPosition; private Quaternion initialRotation; private Rigidbody rb; private XRGrabInteractable grabInteractable; private void Awake() { rb = GetComponent(); grabInteractable = GetComponent(); // 初期スポーン位置・回転を記憶しておく initialPosition = transform.position; initialRotation = transform.rotation; } private void OnTriggerEnter(Collider other) { if (isConnected) return; PuzzleBlock partner = other.GetComponentInParent(); if (partner != null && IsValidPartner(partner)) { nearbyPartner = partner; Debug.Log($"🧩 パートナー検知: {partner.Color} の {partner.ShapeType}"); } } private void OnTriggerExit(Collider other) { PuzzleBlock partner = other.GetComponentInParent(); if (partner == nearbyPartner) { nearbyPartner = null; } } private bool IsValidPartner(PuzzleBlock partner) { if (partner == null || partner.isConnected) return false; // 同一色 & 異なる形状(ト字 + コ字)のみ許可 return partner.Color == this.Color && partner.ShapeType != this.ShapeType; } public void OnReleased() { if (isConnected) return; if (nearbyPartner != null) { ConnectToPartner(nearbyPartner); } } private void ConnectToPartner(PuzzleBlock partner) { isConnected = true; partner.isConnected = true; // 1. 位置・回転のスナップ補正 if (snapPoint != null && partner.snapPoint != null) { transform.position = partner.snapPoint.position; transform.rotation = partner.snapPoint.rotation; } else { transform.position = partner.transform.position; transform.rotation = partner.transform.rotation; } // 2. 物理&VR掴み動作の完全ロック(完成後に崩れないようにする) LockBlockState(); partner.LockBlockState(); Debug.Log($"🎉 マグネット合体成功! 色: {Color}"); // 3. バフ適用してCodingMode完了へ string buffName = ConvertColorToBuffName(Color); PlayerStatusManager.Instance.ApplyBuffsAndResume(buffName, buffName); } private void LockBlockState() { if (rb != null) { rb.linearVelocity = Vector3.zero; rb.angularVelocity = Vector3.zero; rb.isKinematic = true; } // 掴みコンポーネントをオフにして手から切り離す if (grabInteractable != null) grabInteractable.enabled = false; } public void ResetBlock() { isConnected = false; nearbyPartner = null; transform.position = initialPosition; transform.rotation = initialRotation; if (rb != null) { rb.isKinematic = false; rb.linearVelocity = Vector3.zero; rb.angularVelocity = Vector3.zero; } if (grabInteractable != null) grabInteractable.enabled = true; } public static void ResetAllBlocksInScene() { foreach (var block in FindObjectsByType(FindObjectsSortMode.None)) { if (block != null) block.ResetBlock(); } } private string ConvertColorToBuffName(BlockColor color) { return color switch { BlockColor.Red => "AttackUp", BlockColor.Blue => "DefenseUp", BlockColor.Green => "Heal", _ => "AttackUp" }; } }