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>
This commit is contained in:
@@ -0,0 +1,234 @@
|
||||
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 );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user