Files
BeatSaber/Assets/VRBeatsKit/Modules/VRSDK/VR/VR_Interactable.cs
T
whdwo798 4dad9e5d5b feat: SongCreator 씬 완성 — Beat Sage URL 지원, info.dat 메타데이터 자동 추출
- BeatSageUploader: audio_url 지원(UploadFromUrl), PollAndDownload 공통화, ZIP 500 오류 3회 재시도
- BeatSageConverter: info.dat 파싱(SongMetadata), BPM 자동 감지 → 노트 타이밍 변환에 적용
- SongCreatorManager: title/BPM 필수 입력 제거, 난이도 4개 자동 선택, GenerateFlowFromUrl 버그 수정
- NasPublisher: audioPath null 허용(URL 흐름에서 로컬 파일 없는 경우 스킵)
- .gitignore/.gitattributes 초기 설정

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 23:37:34 +09:00

371 lines
13 KiB
C#

using UnityEngine;
using System.Collections.Generic;
using VRSDK.Events;
namespace VRSDK
{
public enum InteractableType
{
Distance,
Collider
}
//basic class for all interactable components
public class VR_Interactable : MonoBehaviour
{
[SerializeField] protected InteractableType interactableType = InteractableType.Distance;
[SerializeField] protected VR_InputButton interactButton = VR_InputButton.Grip;
[SerializeField] protected float interactDistance = 1.0f;
[SerializeField] protected Collider grabCollider = null;
[SerializeField] protected VR_HandInteractSettings rightHandSettings = new VR_HandInteractSettings();
[SerializeField] protected VR_HandInteractSettings leftHandSettings = new VR_HandInteractSettings();
[SerializeField] protected VR_HandInteractSettings handSettings = new VR_HandInteractSettings();
[SerializeField] protected VR_HandAnimationSettings rightHandAnimationSettings = new VR_HandAnimationSettings();
[SerializeField] protected VR_HandAnimationSettings leftHandAnimationSettings = new VR_HandAnimationSettings();
[SerializeField] protected VR_HandAnimationSettings handAnimationSettings = new VR_HandAnimationSettings();
[SerializeField] protected OnInteractEvent onInteractEvent = null;
[SerializeField] protected bool shareHandInteractionSettings = false;
[SerializeField] protected bool shareHandAnimationSettings = false;
[SerializeField] protected bool useDistanceGrab = false;
public bool UseDistanceGrab { get { return useDistanceGrab; } }
public float DistanceToLeftHand { get; private set; }
public float DistanceToRightHand { get; private set; }
public float InteractDistance { get { return interactDistance; } }
public bool CanInteract
{
get
{
return canInteract;
}
protected set
{
canInteract = value;
if (!canInteract)
{
VR_Highlight h = GetComponent<VR_Highlight>();
if (h != null)
h.UnHighlight(null);
}
}
}
public OnInteractEvent OnInteractEvent { get { return onInteractEvent; } }
public InteractableType InteractableType => interactableType;
protected bool m_buttonWasPressedLeft = false;
protected bool m_buttonWasPressedRight = false;
private bool canInteract = true;
private VR_ControllerInfo rightControllerInfo = null;
private VR_ControllerInfo leftControllerInfo = null;
private List<VR_Controller> activeDistanceGrabControllerList = new List<VR_Controller>();
private Transform cacheTransform = null;
protected Transform thisTransform
{
get
{
if (cacheTransform == null)
{
cacheTransform = transform;
}
return cacheTransform;
}
}
public Transform HighlightPointRightHand
{
get
{
return rightHandSettings.highlightPoint == null ? rightHandSettings.interactPoint : rightHandSettings.highlightPoint;
}
}
public Transform HighlightPointLeftHand
{
get
{
return leftHandSettings.highlightPoint == null ? leftHandSettings.interactPoint : leftHandSettings.highlightPoint;
}
}
public Transform HighlightPointHandSettings
{
get
{
return handSettings.highlightPoint;
}
}
public Transform RightInteractPoint
{
get
{
if (!shareHandInteractionSettings)
return rightHandSettings.interactPoint;
else
return handSettings.interactPoint;
}
}
public Transform LeftInteractPoint
{
get
{
if (!shareHandInteractionSettings)
return rightHandSettings.interactPoint;
else
return handSettings.interactPoint;
}
}
public VR_HandInteractSettings HandSettings { get { return handSettings; } }
public VR_HandInteractSettings RightHandSettings { get { return rightHandSettings; } }
public VR_HandInteractSettings LeftHandSettings { get { return leftHandSettings; } }
public VR_HandAnimationSettings HandAnimationSettings { get { return handAnimationSettings; ; } }
public VR_HandAnimationSettings RightHandAnimationSettings { get { return rightHandAnimationSettings; } }
public VR_HandAnimationSettings LeftHandAnimationSettings { get { return leftHandAnimationSettings; } }
public VR_InputButton InteractButton { get { return interactButton; } }
public Collider GrabCollider => grabCollider;
protected virtual void Awake()
{
//if we dont use per hand settings set general settings as the settings for both hands
if (shareHandInteractionSettings)
{
rightHandSettings = handSettings;
leftHandSettings = handSettings;
}
if (shareHandAnimationSettings)
{
rightHandAnimationSettings = handAnimationSettings;
leftHandAnimationSettings = handAnimationSettings;
}
//register this interactable
VR_Manager.instance.RegisterInteract(this);
//create snap points if we need they
CreateAllSnapPoints();
}
protected virtual void Start()
{
CreateControllersInfo();
}
private void CreateAllSnapPoints()
{
if (rightHandSettings.interactPoint == null)
CreateSnapPoint(rightHandSettings);
if (leftHandSettings.interactPoint == null)
CreateSnapPoint(leftHandSettings);
if (handSettings.interactPoint == null)
CreateSnapPoint(handSettings);
}
private void CreateSnapPoint(VR_HandInteractSettings settings)
{
settings.interactPoint = new GameObject("SnapPoint").transform;
settings.interactPoint.parent = transform;
settings.interactPoint.localPosition = Vector3.zero;
settings.interactPoint.localRotation = Quaternion.identity;
}
private void CreateControllersInfo()
{
rightControllerInfo = new VR_ControllerInfo(VR_Manager.instance.Player.RightController);
leftControllerInfo = new VR_ControllerInfo(VR_Manager.instance.Player.LeftController);
}
private void OnDisable()
{
//this object can be destroyed for 2 reasons
//the programmer calling destroy on the gameobject
// and the UnityEngine closing the game, so if Unity is closing the game
//dont do nothing the game is just closing
if (!VR_Manager.ApplicationIsQuitting)
VR_Manager.instance.RemoveInteract(this);
}
private void OnEnable()
{
VR_Manager.instance.RegisterInteract(this);
}
protected virtual void OnDestroy()
{
//this object can be destroyed for 2 reasons
//the programmer calling destroy on the gameobject
// and the UnityEngine closing the game, so if Unity is closing the game
//dont do nothing the game is just closing
if (!VR_Manager.ApplicationIsQuitting)
VR_Manager.instance.RemoveInteract(this);
}
protected virtual void Update()
{
if (!CanInteract) return;
ProcessControllerInfoInteraction(rightControllerInfo);
ProcessControllerInfoInteraction(leftControllerInfo);
}
private void ProcessControllerInfoInteraction(VR_ControllerInfo info)
{
if (info?.controller == null)
{
return;
}
VR_HandInteractSettings settings = info.controller.ControllerType == VR_ControllerType.Right ? rightHandSettings : leftHandSettings;
Transform highlightPoint = info.controller.ControllerType == VR_ControllerType.Right ? HighlightPointRightHand : HighlightPointLeftHand;
bool ignoreDistance = interactableType == InteractableType.Collider;
//if we are trying to do a distance grab using this controller
if (!ignoreDistance && useDistanceGrab && activeDistanceGrabControllerList != null && activeDistanceGrabControllerList.Count > 0 && activeDistanceGrabControllerList.Contains(info.controller))
{
ignoreDistance = true;
}
if (settings.canInteract && highlightPoint != null)
{
CheckIfShouldInteractWithController(info, ignoreDistance);
}
}
private void CheckIfShouldInteractWithController(VR_ControllerInfo info, bool ignoreDistance)
{
float d = ignoreDistance ? 0.0f : GetDistanceToController(info.controller);
if (d <= interactDistance || ignoreDistance)
{
//the button was alredy pressed when the controller enter the grab range?
if (info.interactionButtonWasPressed)
{
info.UpdateButtonWasPressed(interactButton);
if (info.interactionButtonWasPressed)
{
return;
}
}
if (info.controller.enabled && info.controller.Input.GetButtonDown(interactButton))
{
info.controller.InteractWithNearesObject();
info.interactionButtonWasPressed = true;
}
}
else
{
info.UpdateButtonWasPressed(interactButton);
}
}
/// <summary>
/// Get the distance to the controller
/// </summary>
private float GetDistanceToController(VR_Controller controller)
{
float d = float.MaxValue;
Transform interactPoint = controller.ControllerType == VR_ControllerType.Right ? HighlightPointRightHand : HighlightPointLeftHand;
if (controller.Input.IsConnected() && controller.CurrentGrab == null)
{
d = (interactPoint.position - controller.Position).magnitude;
}
return d;
}
public virtual void Interact(VR_Controller controller)
{
onInteractEvent.Invoke(controller);
}
public bool CanInteractUsingController(VR_Controller controller)
{
if (controller.ControllerType == VR_ControllerType.Right)
return rightHandSettings.canInteract;
if (controller.ControllerType == VR_ControllerType.Left)
return leftHandSettings.canInteract;
return false;
}
public VR_HandInteractSettings GetHandInteractionSettings(VR_Controller controller)
{
if (controller.ControllerType == VR_ControllerType.Right)
return rightHandSettings;
if (controller.ControllerType == VR_ControllerType.Left)
return leftHandSettings;
return null;
}
public VR_HandAnimationSettings GetHandAnimationSettings(VR_Controller controller)
{
if (controller.ControllerType == VR_ControllerType.Right)
return rightHandAnimationSettings;
if (controller.ControllerType == VR_ControllerType.Left)
return leftHandAnimationSettings;
return null;
}
public void SetInteractDistanceViaInspector(float d)
{
interactDistance = d;
}
public void AddActiveDistanceGrabController(VR_Controller controller)
{
if (!useDistanceGrab)
return;
activeDistanceGrabControllerList.Add(controller);
}
public void RemoveActiveDistanceGrabController(VR_Controller controller)
{
if (!useDistanceGrab)
return;
activeDistanceGrabControllerList.Remove(controller);
}
}
public class VR_ControllerInfo
{
public VR_Controller controller = null;
public bool interactionButtonWasPressed = false;
public VR_ControllerInfo(VR_Controller controller)
{
this.controller = controller;
interactionButtonWasPressed = false;
}
public void UpdateButtonWasPressed(VR_InputButton interactButton)
{
interactionButtonWasPressed = controller.Input.GetButtonDown(interactButton);
}
}
}