4dad9e5d5b
- 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>
235 lines
7.3 KiB
C#
235 lines
7.3 KiB
C#
using System;
|
|
using UnityEngine;
|
|
|
|
namespace VRSDK
|
|
{
|
|
public class VR_DistanceGrab : MonoBehaviour
|
|
{
|
|
[SerializeField] private Transform pointerTransform = null;
|
|
[SerializeField] private float grabDistance = 5.0f;
|
|
[SerializeField] private float grabRadius = 0.2f;
|
|
[SerializeField] private bool checkForObstruction = false;
|
|
[SerializeField] private bool guideLineAlwaysVisible = false;
|
|
[SerializeField] private bool canTriggerLineRender = false;
|
|
[SerializeField] private VR_InputButton lineTriggerInput = VR_InputButton.Trigger;
|
|
[SerializeField] private LineRenderer lineRender = null;
|
|
[SerializeField] private LayerMask layerMask = new LayerMask();
|
|
|
|
private VR_Controller controller = null;
|
|
private VR_Grabbable activeGrabbable = null;
|
|
private Collider thisCollider = null;
|
|
public Ray GrabbableRay { get { return new Ray( pointerTransform.position , pointerTransform.forward ); } }
|
|
|
|
|
|
private void Awake()
|
|
{
|
|
controller = GetComponent<VR_Controller>();
|
|
thisCollider = GetComponent<Collider>();
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (controller.CurrentGrab != null)
|
|
{
|
|
if (activeGrabbable != null)
|
|
{
|
|
activeGrabbable.RemoveActiveDistanceGrabController( controller );
|
|
SetActiveGrabbable(null);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//get the closer intersection grabbable
|
|
VR_Grabbable closerGrabbable = GrabbableRaycast();
|
|
|
|
|
|
if (closerGrabbable == null)
|
|
{
|
|
if (activeGrabbable != null)
|
|
{
|
|
activeGrabbable.RemoveActiveDistanceGrabController(controller);
|
|
}
|
|
|
|
SetActiveGrabbable( null );
|
|
|
|
return;
|
|
}
|
|
if (closerGrabbable != null && activeGrabbable == null)
|
|
{
|
|
SetActiveGrabbable(closerGrabbable);
|
|
activeGrabbable.AddActiveDistanceGrabController(controller);
|
|
}
|
|
else if (closerGrabbable != null && activeGrabbable != null && activeGrabbable != closerGrabbable)
|
|
{
|
|
activeGrabbable.RemoveActiveDistanceGrabController( controller );
|
|
activeGrabbable = closerGrabbable;
|
|
activeGrabbable.AddActiveDistanceGrabController( controller );
|
|
controller.SetActiveDistanceGrabbable(activeGrabbable);
|
|
}
|
|
else if (closerGrabbable == null && activeGrabbable != null)
|
|
{
|
|
activeGrabbable.RemoveActiveDistanceGrabController(controller);
|
|
SetActiveGrabbable( null );
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
private VR_Grabbable GrabbableRaycast()
|
|
{
|
|
|
|
RaycastHit[] hitArray = Physics.SphereCastAll( GrabbableRay, grabRadius, grabDistance, layerMask, QueryTriggerInteraction.Ignore);
|
|
float minDistance = Mathf.Infinity;
|
|
VR_Grabbable closerGrabbable = null;
|
|
RaycastHit closerHitInfo = new RaycastHit();
|
|
|
|
for (int n = 0; n < hitArray.Length; n++)
|
|
{
|
|
float d = hitArray[n].distance;
|
|
VR_Grabbable grabbable = VR_Manager.instance.GetGrabbableFromCollider( hitArray[n].collider );
|
|
|
|
|
|
if (d < minDistance && IsValidGrabbableRaycast( hitArray[n] ))
|
|
{
|
|
minDistance = d;
|
|
closerGrabbable = grabbable;
|
|
closerHitInfo = hitArray[n];
|
|
}
|
|
|
|
|
|
}
|
|
|
|
if ( ShouldCheckForObstruction(closerGrabbable) )
|
|
{
|
|
Collider col = GetFirstColliderIntersection( pointerTransform.position, ( closerHitInfo.point - pointerTransform.position ).normalized );
|
|
if (col != closerHitInfo.collider)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
return closerGrabbable;
|
|
}
|
|
|
|
private bool ShouldCheckForObstruction(VR_Grabbable closerGrabbable)
|
|
{
|
|
return closerGrabbable != null && checkForObstruction;
|
|
}
|
|
|
|
private void LateUpdate()
|
|
{
|
|
if ( !HasSomethingToGrab() )
|
|
{
|
|
if ( ShouldRenderLineForward() )
|
|
{
|
|
RenderLineForward();
|
|
}
|
|
else
|
|
{
|
|
ClearLineRender();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
RenderLineToActiveGrabbable();
|
|
|
|
}
|
|
|
|
private bool HasSomethingToGrab()
|
|
{
|
|
return activeGrabbable != null;
|
|
}
|
|
|
|
private bool ShouldRenderLineForward()
|
|
{
|
|
return controller.CurrentGrab == null && ( guideLineAlwaysVisible || ( canTriggerLineRender && controller.Input.GetButton( lineTriggerInput ) ) );
|
|
}
|
|
|
|
private void RenderLineForward()
|
|
{
|
|
lineRender.useWorldSpace = false;
|
|
lineRender.positionCount = 2;
|
|
lineRender.SetPosition( 0, Vector3.zero );
|
|
lineRender.SetPosition( 1, Vector3.forward * ( grabDistance / transform.localScale.z ) );
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
if (lineRender != null)
|
|
{
|
|
lineRender.enabled = false;
|
|
}
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
if (lineRender != null)
|
|
{
|
|
lineRender.enabled = true;
|
|
}
|
|
}
|
|
|
|
private void RenderLineToActiveGrabbable()
|
|
{
|
|
Transform lineEnd = GetLineEndTransform();
|
|
|
|
if (lineEnd == null)
|
|
return;
|
|
|
|
lineRender.useWorldSpace = true;
|
|
lineRender.positionCount = 2;
|
|
lineRender.SetPosition( 0, pointerTransform.position );
|
|
lineRender.SetPosition( 1, lineEnd.position );
|
|
}
|
|
|
|
private Transform GetLineEndTransform()
|
|
{
|
|
Transform lineEnd = activeGrabbable.GetHandInteractionSettings(controller).highlightPoint;
|
|
|
|
if (lineEnd == null)
|
|
lineEnd = activeGrabbable.GetHandInteractionSettings(controller).interactPoint;
|
|
|
|
|
|
return lineEnd;
|
|
}
|
|
|
|
private void ClearLineRender()
|
|
{
|
|
lineRender.positionCount = 0;
|
|
}
|
|
|
|
|
|
private Collider GetFirstColliderIntersection(Vector3 origin , Vector3 dir)
|
|
{
|
|
RaycastHit hitInfo;
|
|
|
|
if (Physics.Raycast( origin, dir, out hitInfo, grabDistance , layerMask , QueryTriggerInteraction.Ignore))
|
|
return hitInfo.collider;
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
private bool IsValidGrabbableRaycast(RaycastHit hitInfo)
|
|
{
|
|
VR_Grabbable grabbable = VR_Manager.instance.GetGrabbableFromCollider(hitInfo.collider);
|
|
return hitInfo.collider != thisCollider && grabbable != null && grabbable.enabled && grabbable.UseDistanceGrab && grabbable.CurrentGrabState == GrabState.UnGrab;
|
|
}
|
|
|
|
private void SetActiveGrabbable(VR_Grabbable grabbable)
|
|
{
|
|
activeGrabbable = grabbable;
|
|
controller.SetActiveDistanceGrabbable( grabbable );
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|