feat: Game scene — SongController bridges custom map to VRBeatsKit

- SongController: loads MP3 + Beat Saber JSON map, runs countdown (3→2→1→GO),
  spawns cubes via VR_BeatManager.Spawn() synced to audioSource.time
- NoteData → SpawnEventInfo mapping: position/lineLayer → x/y, colorType → ColorSide,
  cutDirection → Direction enum
- travelTimeOverride on SpawnEventInfo: each cube's travel time is back-calculated
  from remaining time at spawn moment, so simultaneous notes arrive at hit zone together
  regardless of frame-level spawn delay
- AudioManager: add PlayClip(AudioClip) and CurrentTime property
- VR_BeatManager: respect travelTimeOverride when non-zero
- Settings.asset: targetTravelTime 0.5 → 1.8 for natural Beat Saber approach feel
- SceneBuilder ④: auto-builds Game.unity from SaberStyle, wires SongController refs,
  registers in Build Settings
- LiberationSans SDF fallback updated with NanumGothic for Korean text support
- Remove unused SampleScene

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-22 14:32:25 +09:00
parent 64ef3d64ec
commit 2f6aff7691
13 changed files with 5813 additions and 471 deletions
@@ -41,6 +41,14 @@ namespace VRBeats
audioSource.outputAudioMixerGroup.audioMixer.SetFloat("Pitch", value);
}
public void PlayClip(AudioClip clip)
{
audioSource.clip = clip;
audioSource.Play();
}
public float CurrentTime => audioSource != null ? audioSource.time : 0f;
}
}
@@ -69,18 +69,19 @@ namespace VRBeats
Spawneable clone = Instantiate( spawneable , spawnPosition , Quaternion.Euler( info.rotation ) );
SetSpeedRelativeToPlayZone(info);
clone.Construct(info);
Vector3 finalScale = clone.transform.localScale;
clone.transform.localScale = Vector3.zero;
clone.transform.Move(finalPosition, settings.TargetTravelTime).SetEase(settings.TargetTravelEase).SetOnComplete(delegate
float travelTime = info.travelTimeOverride > 0f ? info.travelTimeOverride : settings.TargetTravelTime;
clone.transform.Move(finalPosition, travelTime).SetEase(settings.TargetTravelEase).SetOnComplete(delegate
{
clone.OnSpawn();
}).SetUpdateMode(Platinio.TweenEngine.UpdateMode.Update);
}).SetUpdateMode(Platinio.TweenEngine.UpdateMode.Update);
clone.transform.ScaleTween(finalScale, settings.TargetTravelTime).SetEase(settings.TargetTravelEase);
clone.transform.ScaleTween(finalScale, travelTime).SetEase(settings.TargetTravelEase);
}
@@ -32,5 +32,7 @@ namespace VRBeats
public Vector3 rotation = Vector3.zero;
public float speed = 2.0f;
public int speedMultiplier = 1;
// 0 이면 Settings.TargetTravelTime 사용, 양수면 해당 시간으로 이동
public float travelTimeOverride = 0f;
}
}