195 lines
5.4 KiB
C#
195 lines
5.4 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using UnityEngine.XR.Interaction.Toolkit;
|
||
using UnityEngine.XR.Interaction.Toolkit.Interactables;
|
||
|
||
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; }
|
||
|
||
[SerializeField] private Transform snapPoint;
|
||
|
||
public static event Action<BlockColor> OnPuzzleCompleted;
|
||
|
||
private static readonly HashSet<PuzzleBlock> allBlocks = new HashSet<PuzzleBlock>();
|
||
|
||
private PuzzleBlock nearbyPartner;
|
||
private bool isConnected;
|
||
|
||
// ★ワールド情報ではなく「親階層」と「ローカル情報」を記憶
|
||
private Transform initialParent;
|
||
private Vector3 initialLocalPosition;
|
||
private Quaternion initialLocalRotation;
|
||
private Vector3 initialLocalScale;
|
||
|
||
private Rigidbody rb;
|
||
private XRGrabInteractable grabInteractable;
|
||
|
||
private void Awake()
|
||
{
|
||
rb = GetComponent<Rigidbody>();
|
||
grabInteractable = GetComponent<XRGrabInteractable>();
|
||
|
||
// ★開始時の「親」と「ローカル座標・回転・スケール」を保持
|
||
initialParent = transform.parent;
|
||
initialLocalPosition = transform.localPosition;
|
||
initialLocalRotation = transform.localRotation;
|
||
initialLocalScale = transform.localScale;
|
||
}
|
||
|
||
private void OnEnable()
|
||
{
|
||
allBlocks.Add(this);
|
||
}
|
||
|
||
private void OnDisable()
|
||
{
|
||
allBlocks.Remove(this);
|
||
}
|
||
|
||
private void OnTriggerEnter(Collider other)
|
||
{
|
||
if (isConnected) return;
|
||
|
||
PuzzleBlock partner = other.GetComponentInParent<PuzzleBlock>();
|
||
if (partner != null && IsValidPartner(partner))
|
||
{
|
||
nearbyPartner = partner;
|
||
}
|
||
}
|
||
|
||
private void OnTriggerExit(Collider other)
|
||
{
|
||
PuzzleBlock partner = other.GetComponentInParent<PuzzleBlock>();
|
||
if (partner == nearbyPartner)
|
||
{
|
||
nearbyPartner = null;
|
||
}
|
||
}
|
||
|
||
private bool IsValidPartner(PuzzleBlock partner)
|
||
{
|
||
if (partner == null || partner.isConnected) return false;
|
||
return partner.Color == Color && partner.ShapeType != ShapeType;
|
||
}
|
||
|
||
public void OnReleased()
|
||
{
|
||
if (isConnected) return;
|
||
|
||
if (nearbyPartner != null)
|
||
{
|
||
ConnectToPartner(nearbyPartner);
|
||
}
|
||
}
|
||
|
||
private void ConnectToPartner(PuzzleBlock partner)
|
||
{
|
||
isConnected = true;
|
||
partner.isConnected = true;
|
||
|
||
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;
|
||
}
|
||
|
||
LockBlockState();
|
||
partner.LockBlockState();
|
||
|
||
OnPuzzleCompleted?.Invoke(Color);
|
||
|
||
BuffType buff = ConvertColorToBuffType(Color);
|
||
if (PlayerStatusManager.Instance != null)
|
||
{
|
||
PlayerStatusManager.Instance.ApplyBuffsAndResume(buff, buff);
|
||
}
|
||
}
|
||
|
||
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()
|
||
{
|
||
// 1. 手で掴んでいる場合は手離し処理
|
||
ForceDrop();
|
||
|
||
isConnected = false;
|
||
nearbyPartner = null;
|
||
|
||
// 2. ★親オブジェクト(Canvas)の子へ戻す
|
||
if (initialParent != null && transform.parent != initialParent)
|
||
{
|
||
transform.SetParent(initialParent, false);
|
||
}
|
||
|
||
// 3. ★Canvas内のローカル位置・回転・スケールを完全復元
|
||
transform.localPosition = initialLocalPosition;
|
||
transform.localRotation = initialLocalRotation;
|
||
transform.localScale = initialLocalScale;
|
||
|
||
// 4. 物理状態の再初期化
|
||
if (rb != null)
|
||
{
|
||
rb.isKinematic = false;
|
||
rb.linearVelocity = Vector3.zero;
|
||
rb.angularVelocity = Vector3.zero;
|
||
}
|
||
|
||
// 5. 掴み機能の再有効化
|
||
if (grabInteractable != null)
|
||
{
|
||
grabInteractable.enabled = true;
|
||
}
|
||
}
|
||
|
||
private void ForceDrop()
|
||
{
|
||
if (grabInteractable == null || !grabInteractable.isSelected) return;
|
||
|
||
if (grabInteractable.interactionManager != null && grabInteractable.firstInteractorSelecting != null)
|
||
{
|
||
grabInteractable.interactionManager.SelectExit(grabInteractable.firstInteractorSelecting, grabInteractable);
|
||
}
|
||
}
|
||
|
||
public static void ResetAllBlocksInScene()
|
||
{
|
||
foreach (var block in allBlocks)
|
||
{
|
||
if (block != null)
|
||
{
|
||
block.ResetBlock();
|
||
}
|
||
}
|
||
}
|
||
|
||
private BuffType ConvertColorToBuffType(BlockColor color)
|
||
{
|
||
return color switch
|
||
{
|
||
BlockColor.Red => BuffType.AttackUp,
|
||
BlockColor.Blue => BuffType.DefenseUp,
|
||
BlockColor.Green => BuffType.Heal,
|
||
_ => BuffType.AttackUp
|
||
};
|
||
}
|
||
} |