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,155 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace VRSDK.Locomotion
|
||||
{
|
||||
//this scripts handle the raycasting part for teleporting
|
||||
public abstract class VR_AimRaycaster : MonoBehaviour
|
||||
{
|
||||
[Tooltip( "How many subdivisions will have the teleport ray?, this could increase the numbers of linecast per frame, be careful." )]
|
||||
[SerializeField] [Range(1 , 25)] protected int collisionAccuracy = 8;
|
||||
[SerializeField] protected float validAngle = 60.0f;
|
||||
[SerializeField] protected float invalidRayDistance = 2.0f;
|
||||
[SerializeField] protected LayerMask validLayerMask;
|
||||
|
||||
public virtual AimRaycastInfo Raycast(List<Vector3> points , Transform rayController)
|
||||
{
|
||||
//get rayController angle
|
||||
Vector3 rayControllerForward = rayController.forward;
|
||||
Vector3 unalteredForward = new Vector3( rayController.forward.x, 0.0f, rayController.forward.z ).normalized;
|
||||
float angle = Vector3.Angle( rayController.forward, unalteredForward );
|
||||
|
||||
//check if we are on a valid angle
|
||||
if (angle > validAngle)
|
||||
{
|
||||
AimRaycastInfo info = new AimRaycastInfo();
|
||||
info.hitPoint = Vector3.zero;
|
||||
info.normal = Vector3.zero;
|
||||
//clamp ray to a distance
|
||||
info.validPoints = ClampToDistance(points , invalidRayDistance );
|
||||
info.isValid = false;
|
||||
|
||||
return info;
|
||||
|
||||
}
|
||||
|
||||
//the points are valid?
|
||||
if (points.Count <= 1)
|
||||
return null;
|
||||
|
||||
RaycastHit hitInfo;
|
||||
|
||||
if (points.Count == 2)
|
||||
{
|
||||
if (Physics.Linecast( points[0], points[1] , out hitInfo , validLayerMask.value , QueryTriggerInteraction.Ignore))
|
||||
{
|
||||
return ProcessHitInfo(hitInfo , new List<Vector3> { points[0] , hitInfo.point } );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
List<Vector3> validPoints = new List<Vector3>();
|
||||
|
||||
int subdivision = Mathf.CeilToInt( points.Count / collisionAccuracy);
|
||||
int currentIndex = 0;
|
||||
int nextIndex = subdivision;
|
||||
|
||||
for (int n = 0; n < subdivision; n++)
|
||||
{
|
||||
//check for collision in this segment
|
||||
if (Physics.Linecast( points[currentIndex], points[nextIndex] , validLayerMask.value , QueryTriggerInteraction.Ignore))
|
||||
{
|
||||
//found a collision in this segment
|
||||
//find collision in all points inside this segment
|
||||
for (int j = currentIndex; j < nextIndex; j++)
|
||||
{
|
||||
validPoints.Add( points[j] );
|
||||
|
||||
if (Physics.Linecast( points[j], points[j + 1], out hitInfo , validLayerMask.value , QueryTriggerInteraction.Ignore))
|
||||
{
|
||||
validPoints.Add( hitInfo.point );
|
||||
return ProcessHitInfo(hitInfo , validPoints);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//this segment dont has a collision, addall as valid points
|
||||
for (int j = currentIndex; j <= nextIndex; j++)
|
||||
{
|
||||
validPoints.Add( points[j] );
|
||||
}
|
||||
}
|
||||
|
||||
//move to the next subdivision if we have one
|
||||
currentIndex += subdivision;
|
||||
nextIndex += subdivision;
|
||||
|
||||
//we found the end
|
||||
if (currentIndex >= points.Count)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (nextIndex >= points.Count)
|
||||
nextIndex = points.Count - 1;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected abstract AimRaycastInfo ProcessHitInfo(RaycastHit hitInfo, List<Vector3> validPoints);
|
||||
|
||||
|
||||
private List<Vector3> ClampToDistance(List<Vector3> points , float d)
|
||||
{
|
||||
List<Vector3> validPoints = new List<Vector3>();
|
||||
|
||||
float currentSqrDistance = 0.0f;
|
||||
|
||||
for (int n = 0; n < points.Count - 1; n++)
|
||||
{
|
||||
float distance = (points[n] - points[n + 1]).sqrMagnitude;
|
||||
|
||||
validPoints.Add( points[n] );
|
||||
|
||||
if (distance + currentSqrDistance < d * d)
|
||||
{
|
||||
currentSqrDistance += distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 dir = ( points[n + 1] - points[n] ).normalized;
|
||||
float diff = Mathf.Abs( Mathf.Abs( Mathf.Sqrt( currentSqrDistance ) ) - Mathf.Abs( d ) );
|
||||
|
||||
validPoints.Add( points[n] + (dir * diff) );
|
||||
|
||||
return validPoints;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return validPoints;
|
||||
}
|
||||
|
||||
protected float GetSlopeAngle(Vector3 surfaceNormal)
|
||||
{
|
||||
return Vector3.Angle(surfaceNormal , Vector3.up);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class AimRaycastInfo
|
||||
{
|
||||
public Vector3 hitPoint = Vector3.zero;
|
||||
public Vector3 normal = Vector3.zero;
|
||||
public List<Vector3> validPoints = new List<Vector3>();
|
||||
public bool isValid = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user