using UnityEngine; namespace Watermelon { /// /// Manages haptic feedback across platforms (iOS, Android, WebGL, Editor). /// Create an instance via new Haptic() (e.g. from ) to activate the module, /// then use the static facade methods to trigger feedback. /// public class Haptic { private static Haptic instance; /// Predefined light haptic feedback (short, low intensity). public static readonly HapticData HAPTIC_LIGHT = new HapticData(0.14f, 0.4f); /// Predefined medium haptic feedback. public static readonly HapticData HAPTIC_MEDIUM = new HapticData(0.14f, 0.6f); /// Predefined strong haptic feedback. public static readonly HapticData HAPTIC_HARD = new HapticData(0.14f, 0.8f); /// Predefined light haptic pattern. public static readonly HapticPattern PATTERN_LIGHT = new HapticPattern("light", new HapticEvent[] { new() { Duration = 0.3f, Intensity = 1.0f, Sharpness = 0.0f, StartTime = 0.0f } }); private bool isActive; private readonly HapticSave save; private readonly BaseHapticWrapper wrapper; /// Fires when haptic is enabled or disabled. public static event SimpleBoolCallback StateChanged; /// /// Whether haptic feedback is currently enabled. Persisted across sessions. /// Returns false if the module has not been created yet. /// public static bool IsActive { get => IsInitialized && instance.isActive; set { if (!IsInstanceExists()) return; instance.isActive = value; instance.save.IsActive = value; SaveController.MarkAsSaveIsRequired(); LogManager.Log($"[Haptic]: State changed: {(value ? "Active" : "Disabled")}", LogCategory.Systems); StateChanged?.Invoke(value); } } /// Returns true if an instance has been created. public static bool IsInitialized => instance != null; /// /// Creates the haptic module instance, loads saved state and sets up the platform wrapper. /// The constructor registers itself as the active instance. /// public Haptic() { instance = this; save = SaveController.GetSaveObject("haptic"); isActive = save.IsActive; wrapper = GetPlatformWrapper(); if (wrapper == null) { LogManager.LogWarning("[Haptic]: Unsupported platform", LogCategory.Systems); return; } wrapper.Init(); wrapper.RegisterPattern(PATTERN_LIGHT); } /// /// Registers a custom haptic pattern so it can be triggered via or . /// public static void RegisterPattern(HapticPattern hapticPattern) { if (!IsInstanceExists()) return; if (instance.wrapper == null) return; instance.wrapper.RegisterPattern(hapticPattern); } /// Plays haptic feedback using a preset. public static void Play(HapticData hapticData) { Play(hapticData.Duration, hapticData.Intensity); } /// Plays haptic feedback with the given duration (seconds) and intensity (0–1). public static void Play(float duration, float intensity = 1.0f) { if (!IsActive) return; if (instance.wrapper == null) return; if (duration <= 0) return; instance.wrapper.Play(duration, intensity); } /// Plays a registered . public static void Play(HapticPattern pattern) { if (!IsActive) return; if (instance.wrapper == null) return; instance.wrapper.Play(pattern.ID); } /// Plays a registered haptic pattern by its string ID. public static void Play(string patternID) { if (!IsActive) return; if (instance.wrapper == null) return; instance.wrapper.Play(patternID); } /// Releases the module instance and clears all state. public static void Unload() { instance = null; StateChanged = null; } private static bool IsInstanceExists() { if (instance == null) { LogManager.LogWarning("[Haptic]: Module is not initialized. Create a Haptic instance first.", LogCategory.Systems); return false; } return true; } public static BaseHapticWrapper GetPlatformWrapper() { #if UNITY_EDITOR return new EditorHapticWrapper(); #elif UNITY_IOS return new IOSHapticWrapper(); #elif UNITY_ANDROID return new AndroidHapticWrapper(); #elif UNITY_WEBGL return new WebGLHapticWrapper(); #else return null; #endif } } }