using UnityEngine; using UnityEngine.XR.Interaction.Toolkit; using UnityEngine.XR.Interaction.Toolkit.Interactors; /// /// 3D空間上の2つのソケットスロットにバフモジュールがハメ込まれたかを監視し、 /// 連結完了時にバフを発動させるパズル管理クラス /// public class CodingPuzzleManager : MonoBehaviour { [Header("ソケットスロットの設定")] [Tooltip("台座に配置した Slot_A の XRSocketInteractor を指定してください")] [SerializeField] private XRSocketInteractor socketA; [Tooltip("台座に配置した Slot_B の XRSocketInteractor を指定してください")] [SerializeField] private XRSocketInteractor socketB; private void OnEnable() { // ソケットにオブジェクトが「ハメ込まれた瞬間」のイベントを登録 if (socketA != null) socketA.selectEntered.AddListener(OnSocketAEntered); if (socketB != null) socketB.selectEntered.AddListener(OnSocketBEntered); } private void OnDisable() { // イベントの登録解除 if (socketA != null) socketA.selectEntered.RemoveListener(OnSocketAEntered); if (socketB != null) socketB.selectEntered.RemoveListener(OnSocketBEntered); } // Slot_A に何かがハメ込まれた時のコールバック private void OnSocketAEntered(SelectEnterEventArgs args) { CheckPuzzleCompletion(); } // Slot_B に何かがハメ込まれた時のコールバック private void OnSocketBEntered(SelectEnterEventArgs args) { CheckPuzzleCompletion(); } /// /// 両方のスロットが埋まっているかチェックし、埋まっていれば連結バフを発動する /// private void CheckPuzzleCompletion() { if (socketA == null || socketB == null) return; // 両方のソケットがオブジェクトを保持(hasSelection)しているか確認 if (socketA.hasSelection && socketB.hasSelection) { // ハメ込まれているオブジェクト(Interactable)を取得 var objA = socketA.firstInteractableSelected; var objB = socketB.firstInteractableSelected; if (objA != null && objB != null) { // オブジェクトの名前から、どのバフ四角形かを判別する文字列を抽出 string buff1 = GetBuffNameFromObjectName(objA.transform.gameObject.name); string buff2 = GetBuffNameFromObjectName(objB.transform.gameObject.name); Debug.Log($"💻 パズル連結完了! 検出されたコンボ: [{buff1}] + [{buff2}]"); // ★ソケットにハマっているオブジェクトを強制的に解放・リセット // (これをしないと、次回Codingモードを開いた時にスロットが埋まったままになります) ClearSockets(); // PlayerStatusManagerにバフを適用させ、時間停止を解除してプレイ画面に戻る if (PlayerStatusManager.Instance != null) { PlayerStatusManager.Instance.ApplyBuffsAndResume(buff1, buff2); } } } } /// /// オブジェクト名に含まれるキーワードから、ステータスマネージャーに渡す用の正確なバフ名を返すヘルパー /// private string GetBuffNameFromObjectName(string objName) { if (objName.Contains("AttackUp")) return "AttackUp"; if (objName.Contains("DefenseUp")) return "DefenseUp"; if (objName.Contains("Heal")) return "Heal"; return "Unknown"; } /// /// 次回起動時のために、ソケットの選択状態を内部的・物理的に安全にクリアする /// private void ClearSockets() { // 開発環境のSDKバージョンによって挙動が異なる場合があるため、 // ハハマっているモジュールを一度ソケットの子供から外し、初期位置付近に戻すか、 // あるいは単純に非アクティブ(または位置リセット)にする処理が推奨されます。 // ここでは安全のため、ハマっていたオブジェクトの座標を台座の手前に逃がします。 if (socketA.firstInteractableSelected != null) { socketA.firstInteractableSelected.transform.position = transform.position + (transform.forward * -0.2f); } if (socketB.firstInteractableSelected != null) { socketB.firstInteractableSelected.transform.position = transform.position + (transform.forward * -0.2f) + (transform.right * 0.1f); } } }