using SmoothShakeFree; using UnityEngine; public class effectEventController : MonoBehaviour { public enum CameraOffsetAxis { X, Y, Z } public static effectEventController Instance { get; private set; } [Header("Multi Note Screen Shake")] public bool enableMultiNoteScreenShake = true; public float multiNoteScreenShakeAmplitude = 0.08f; [Header("Camera Drift")] public bool enableCameraDrift = false; public Vector2 cameraDriftRange = new Vector2(0.15f, 0.08f); public float cameraDriftSpeed = 0.3f; [Header("Player Skill 10 Camera Offset")] public float playerSkillCameraOffsetAmount = 0.6f; public CameraOffsetAxis playerSkillCameraOffsetAxis = CameraOffsetAxis.Y; [Header("Track Crash")] [SerializeField] private TrackCrashController trackCrashController; private Transform cachedShakeTarget; private Transform cachedCameraDriftPivot; private Transform cachedCameraSkillPivot; private Vector3 cameraDriftBaseLocalPosition; private Vector3 cameraSkillBaseLocalPosition; private float cameraDriftSeedX; private float cameraDriftSeedY; private void Awake() { if (Instance == null) { Instance = this; cameraDriftSeedX = Random.Range(0f, 1000f); cameraDriftSeedY = Random.Range(1000f, 2000f); CacheShakeTarget(); return; } if (Instance != this) { Destroy(gameObject); } } private void OnEnable() { CacheShakeTarget(); ResetCameraDriftIfNeeded(); CacheTrackCrashController(); } private void Update() { UpdateCameraDrift(); UpdatePlayerSkillCameraOffset(); } private void CacheShakeTarget() { if (Camera.main != null) { cachedShakeTarget = Camera.main.transform; PrewarmShakeComponent(); EnsureCameraDriftPivot(); EnsureCameraSkillPivot(); } } private void CacheTrackCrashController() { if (trackCrashController == null) { trackCrashController = SceneObjectLookupCache.FindAny(); } } private void PrewarmShakeComponent() { if (cachedShakeTarget == null) return; SmoothShake shake = cachedShakeTarget.GetComponent(); if (shake == null) { shake = cachedShakeTarget.gameObject.AddComponent(); } if (shake.positionShake == null) shake.positionShake = new Shaker(); if (shake.rotationShake == null) shake.rotationShake = new Shaker(); if (shake.shakers == null || shake.shakers.Length != 2) shake.shakers = new[] { shake.positionShake, shake.rotationShake }; if (shake.sum == null || shake.sum.Length != 2) shake.sum = new Vector3[2]; } private void EnsureCameraDriftPivot() { if (cachedShakeTarget == null) return; if (cachedCameraDriftPivot != null) return; Transform currentParent = cachedShakeTarget.parent; if (currentParent != null && currentParent.name == "__effect_event_camera_drift_pivot") { cachedCameraDriftPivot = currentParent; cameraDriftBaseLocalPosition = cachedCameraDriftPivot.localPosition; return; } GameObject pivotObject = new GameObject("__effect_event_camera_drift_pivot"); Transform pivot = pivotObject.transform; if (currentParent != null) { pivot.SetParent(currentParent, false); pivot.localPosition = cachedShakeTarget.localPosition; pivot.localRotation = cachedShakeTarget.localRotation; pivot.localScale = Vector3.one; } else { pivot.position = cachedShakeTarget.position; pivot.rotation = cachedShakeTarget.rotation; } cachedShakeTarget.SetParent(pivot, true); cachedShakeTarget.localRotation = Quaternion.identity; cachedCameraDriftPivot = pivot; cameraDriftBaseLocalPosition = cachedCameraDriftPivot.localPosition; } private void EnsureCameraSkillPivot() { if (cachedShakeTarget == null) return; if (cachedCameraSkillPivot != null) return; Transform currentParent = cachedShakeTarget.parent; if (currentParent != null && currentParent.name == "__effect_event_camera_skill_pivot") { cachedCameraSkillPivot = currentParent; cameraSkillBaseLocalPosition = cachedCameraSkillPivot.localPosition; return; } GameObject pivotObject = new GameObject("__effect_event_camera_skill_pivot"); Transform pivot = pivotObject.transform; if (currentParent != null) { pivot.SetParent(currentParent, false); pivot.localPosition = cachedShakeTarget.localPosition; pivot.localRotation = cachedShakeTarget.localRotation; pivot.localScale = Vector3.one; } else { pivot.position = cachedShakeTarget.position; pivot.rotation = cachedShakeTarget.rotation; pivot.localScale = Vector3.one; } cachedShakeTarget.SetParent(pivot, true); cachedShakeTarget.localPosition = Vector3.zero; cachedShakeTarget.localRotation = Quaternion.identity; cachedCameraSkillPivot = pivot; cameraSkillBaseLocalPosition = cachedCameraSkillPivot.localPosition; } private void UpdateCameraDrift() { if (cachedShakeTarget == null) { CacheShakeTarget(); } if (cachedShakeTarget == null) return; EnsureCameraDriftPivot(); if (cachedCameraDriftPivot == null) return; if (!enableCameraDrift) { ResetCameraDriftIfNeeded(); return; } float speed = Mathf.Max(0f, cameraDriftSpeed); float time = GameplayClock.NowSongTime * speed; float offsetX = (Mathf.PerlinNoise(cameraDriftSeedX, time) - 0.5f) * 2f * Mathf.Abs(cameraDriftRange.x); float offsetY = (Mathf.PerlinNoise(cameraDriftSeedY, time) - 0.5f) * 2f * Mathf.Abs(cameraDriftRange.y); cachedCameraDriftPivot.localPosition = cameraDriftBaseLocalPosition + new Vector3(offsetX, offsetY, 0f); } private void ResetCameraDriftIfNeeded() { if (cachedCameraDriftPivot == null) return; cachedCameraDriftPivot.localPosition = cameraDriftBaseLocalPosition; } private void UpdatePlayerSkillCameraOffset() { if (cachedShakeTarget == null) { CacheShakeTarget(); } if (cachedShakeTarget == null) return; EnsureCameraSkillPivot(); if (cachedCameraSkillPivot == null) return; Vector3 targetLocalPosition = cameraSkillBaseLocalPosition; if (PlayerSkillService.IsSkillEnabled(10)) { float offset = playerSkillCameraOffsetAmount; switch (playerSkillCameraOffsetAxis) { case CameraOffsetAxis.X: targetLocalPosition.x += offset; break; case CameraOffsetAxis.Y: targetLocalPosition.y += offset; break; case CameraOffsetAxis.Z: targetLocalPosition.z += offset; break; } } if (cachedCameraSkillPivot.localPosition != targetLocalPosition) { cachedCameraSkillPivot.localPosition = targetLocalPosition; } } public static void RefreshPlayerSkillCameraOffset() { effectEventController controller = Instance != null ? Instance : SceneObjectLookupCache.FindAny(); if (controller == null) return; controller.CacheShakeTarget(); controller.UpdatePlayerSkillCameraOffset(); } public static void TryTriggerMultiNoteShake() { effectEventController controller = Instance != null ? Instance : SceneObjectLookupCache.FindAny(); if (controller == null) return; controller.TriggerMultiNoteShakeInternal(); } public static void TryTriggerTrackCrash(int trackIndex) { effectEventController controller = Instance != null ? Instance : SceneObjectLookupCache.FindAny(); if (controller == null) return; controller.TriggerTrackCrashInternal(trackIndex); } private void TriggerMultiNoteShakeInternal() { if (!enableMultiNoteScreenShake) return; if (cachedShakeTarget == null) { CacheShakeTarget(); } if (cachedShakeTarget == null) return; float amplitudeValue = Mathf.Max(0f, multiNoteScreenShakeAmplitude); if (amplitudeValue <= 0f) return; SmoothShake shake = cachedShakeTarget.GetComponent(); if (shake == null) { shake = cachedShakeTarget.gameObject.AddComponent(); } if (shake.positionShake == null) shake.positionShake = new Shaker(); if (shake.rotationShake == null) shake.rotationShake = new Shaker(); shake.positionShake.noiseType = Shaker.NoiseType.SineWave; shake.positionShake.amplitude = new Vector3(amplitudeValue, amplitudeValue, 0f); shake.positionShake.frequency = new Vector3(20f, 20f, 0f); shake.rotationShake.amplitude = Vector3.zero; shake.rotationShake.frequency = Vector3.zero; shake.timeSettings.constantShake = false; shake.timeSettings.fadeInDuration = 0.03f; shake.timeSettings.holdDuration = 0.04f; shake.timeSettings.fadeOutDuration = 0.05f; if (shake.timeSettings.fadeInCurve == null || shake.timeSettings.fadeInCurve.length == 0) shake.timeSettings.fadeInCurve = AnimationCurve.Linear(0f, 0f, 1f, 1f); if (shake.timeSettings.fadeOutCurve == null || shake.timeSettings.fadeOutCurve.length == 0) shake.timeSettings.fadeOutCurve = AnimationCurve.Linear(0f, 1f, 1f, 0f); shake.shakers = new[] { shake.positionShake, shake.rotationShake }; shake.sum = new Vector3[2]; shake.StartShake(); } private void TriggerTrackCrashInternal(int trackIndex) { CacheTrackCrashController(); if (trackCrashController == null) return; trackCrashController.TriggerTrackCrash(trackIndex); } }