#nullable enable using System.Collections; using UnityEngine; using Cinemachine; using UnityEngine.InputSystem; public class ScreenShaker : MonoBehaviour { CinemachineVirtualCamera cam = null!; CinemachineBasicMultiChannelPerlin noise = null!; Coroutine? coroutine; (float, float)? heldRumble; void Awake() { cam = GetComponent(); noise = cam.GetCinemachineComponent(); } public void Shake(float magnitude = 1f, float rumbleLowFreq = 0.25f, float rumbleHighFreq = 0.75f, float duration = 0.2f) { if (coroutine is {}) StopCoroutine(coroutine); coroutine = StartCoroutine(ShakeCoroutine(magnitude, rumbleLowFreq, rumbleHighFreq, duration)); } public void StartHeldRumble(float rumbleLowFreq = 0.25f, float rumbleHighFreq = 0.75f) { heldRumble = (rumbleLowFreq, rumbleHighFreq); Gamepad.current.SetMotorSpeeds(rumbleLowFreq, rumbleHighFreq); } public void StopHeldRumble() { heldRumble = null; Gamepad.current.ResetHaptics(); } IEnumerator ShakeCoroutine(float magnitude, float rumbleLowFreq, float rumbleHighFreq, float duration) { noise.m_AmplitudeGain = magnitude; noise.m_FrequencyGain = 10f; Gamepad.current.SetMotorSpeeds(rumbleLowFreq, rumbleHighFreq); yield return new WaitForSecondsRealtime(duration); noise.m_AmplitudeGain = 0f; noise.m_FrequencyGain = 1f; if (heldRumble != null) Gamepad.current.SetMotorSpeeds(heldRumble.Value.Item1, heldRumble.Value.Item2); else Gamepad.current.ResetHaptics(); } }