Interhaptics SDK for Unity 1.6
Loading...
Searching...
No Matches
HAR.cs
Go to the documentation of this file.
1/* ​
2* Copyright (c) 2023 Go Touch VR SAS. All rights reserved. ​
3* ​
4*/
5
6using System.Collections.Generic;
7using UnityEngine;
11using System.Collections;
12
13namespace Interhaptics.Core
14{
15 public static partial class HAR
16 {
17
18 #region Constants
19 public const double DEFAULT_FREQ_MIN = 65.0;
20 public const double DEFAULT_FREQ_MAX = 300.0;
21 public const double DEFAULT_INTENSITY = 1.0;
22 public const int DEFAULT_LOOPS = 1;
23 public const double DELAY_COMPENSATION = 0.02;
24 public const LateralFlag DEFAULT_CONTROLLER_SIDE = LateralFlag.Global;
25 #endregion
26
27 // Flag to indicate if the haptic effect should be stopped
28 public static bool stopHapticEffect = false;
29
30 #region Enums
31 public enum HMaterial_VersionStatus
32 {
33 NoAnHapticsMaterial = 0,
34 V3_NeedToBeReworked = 1,
35 V4_Current = 2,
36 UnknownVersion = 3
37 }
38 #endregion
39
40 #region Haptic Material/Effect Management
41 private static string parseMaterial(UnityEngine.TextAsset _material)
42 {
43 if (_material == null)
44 {
45 return "";
46 }
47 return _material.text;
48 }
49
50 private static string parseMaterial(HapticMaterial _material)
51 {
52 if (_material == null)
53 {
54 return "";
55 }
56 return _material.text;
57 }
58
64 public static int AddHMString(string jsonContent)
65 {
66 return HAR.AddHM(jsonContent);
67 }
68
74 public static int AddHM(UnityEngine.TextAsset _material)
75 {
76 return AddHM(parseMaterial(_material));
77 }
78
84 public static int AddHM(HapticMaterial _material)
85 {
86 return AddHM(parseMaterial(_material));
87 }
88
95 public static bool UpdateHM(int _id, UnityEngine.TextAsset _material)
96 {
97 return UpdateHM(_id, parseMaterial(_material));
98 }
99
106 public static bool UpdateHM(int _id, HapticMaterial _material)
107 {
108 return UpdateHM(_id, parseMaterial(_material));
109 }
110 #endregion
111
117 public static void AddTargetToEvent(int _hMaterialId, List<CommandData> _target)
118 {
119 AddTargetToEventMarshal(_hMaterialId, _target.ToArray(), _target.Count);
120 }
121
129 public static void UpdateEventPositions(int _hMaterialId, List<CommandData> _target, double _texturePosition, double _stiffnessPosition)
130 {
131 UpdateEventPositionsMarshal(_hMaterialId, _target.ToArray(), _target.Count, _texturePosition, _stiffnessPosition);
132 }
133
139 public static void RemoveTargetFromEvent(int _hMaterialId, List<CommandData> _target)
140 {
141 RemoveTargetFromEventMarshal(_hMaterialId, _target.ToArray(), _target.Count);
142 }
143
150 public static void SetTargetIntensity(int _hMaterialId, List<CommandData> _target, double _intensity)
151 {
152 SetTargetIntensityMarshal(_hMaterialId, _target.ToArray(), _target.Count, _intensity);
153 }
154
159 public static void DebugAPIMode(string message)
160 {
161 if (HapticManager.DebugSwitch)
162 {
163 Debug.Log(message);
164 }
165 }
166
174 public static void PlayHapticEffect(HapticMaterial material, double intensity = DEFAULT_INTENSITY, int loops = DEFAULT_LOOPS, float vibrationOffset = 0f, LateralFlag controllerSide = DEFAULT_CONTROLLER_SIDE)
175 {
176#if (UNITY_ANDROID && !ENABLE_METAQUEST && !ENABLE_OPENXR && !UNITY_EDITOR) || UNITY_IOS
177 MobileControl.StopEffects();
178 HAR.StopAllEvents();
179#endif
180 int hMaterialId = AddHM(material);
181 if (hMaterialId == -1)
182 {
183 DebugAPIMode("PlayHapticEffect: Failed to add haptic effect.");
184 return;
185 }
186 List<CommandData> targets = new List<CommandData> { new CommandData(Operator.Plus, GroupID.Palm, controllerSide) };
187 AddTargetToEvent(hMaterialId, targets);
188 SetEventIntensity(hMaterialId, intensity);
189 SetEventLoop(hMaterialId, loops);
190 PlayEvent(hMaterialId, (double)-Time.realtimeSinceStartup, 0, 0);
191 double duration = HAR.GetVibrationLength(hMaterialId);
192#if (UNITY_ANDROID && !ENABLE_METAQUEST && !ENABLE_OPENXR && !UNITY_EDITOR) || UNITY_IOS
193 MobileControl.EnqueueEffect(hMaterialId, duration, loops, intensity, vibrationOffset);
194 HAR.PlayEvent(hMaterialId, (double)-Time.realtimeSinceStartup, 0, 0);
195#endif
196 DebugAPIMode($"PlayHapticEffect: Enqueued haptic effect with Material ID {hMaterialId}, Loops {loops}, Intensity {intensity}, Controller Side {controllerSide}.");
197 }
198
206 public static void PlayHapticEffectId(int hMaterialId, double intensity = DEFAULT_INTENSITY, int loops = DEFAULT_LOOPS, float vibrationOffset = 0f, LateralFlag controllerSide = DEFAULT_CONTROLLER_SIDE)
207 {
208#if (UNITY_ANDROID && !ENABLE_METAQUEST && !ENABLE_OPENXR && !UNITY_EDITOR) || UNITY_IOS
209 MobileControl.StopEffects();
210 HAR.StopAllEvents();
211#endif
212 if (hMaterialId == -1)
213 {
214 DebugAPIMode("PlayHapticEffectId: Failed to add haptic material.");
215 return;
216 }
217 double duration = HAR.GetVibrationLength(hMaterialId);
218 SetEventIntensity(hMaterialId, intensity);
219 SetEventLoop(hMaterialId, loops);
220#if (UNITY_ANDROID && !ENABLE_METAQUEST && !ENABLE_OPENXR && !UNITY_EDITOR) || UNITY_IOS
221 MobileControl.EnqueueEffect(hMaterialId, duration, loops, intensity, vibrationOffset);
222#else
223 HAR.PlayEvent(hMaterialId, (double)-Time.realtimeSinceStartup - vibrationOffset, 0, 0);
224#endif
225 DebugAPIMode($"PlayHapticEffectId: Enqueued haptic effect with Material ID {hMaterialId}, Loops {loops}, Intensity {intensity}, Controller Side {controllerSide}.");
226 }
227
228 public static void PlayParametricHapticEffect(double[] _amplitude, double[] _pitch, double _freqMin, double _freqMax, double[] _transient, double _intensity, int _loops, LateralFlag _controllerSide)
229 {
230#if (UNITY_ANDROID && !ENABLE_METAQUEST && !ENABLE_OPENXR && !UNITY_EDITOR) || UNITY_IOS
231 HAR.StopAllEvents();
232 MobileControl.StopEffects();
233 //only one event allowed for mobile
234#endif
235 if (_transient != null)
236 {
237 if (_transient[0] == 0.0)
238 { // If the first transient is at time 0, add a small delay to compensate for the delay in the system
239 _transient[0] = DELAY_COMPENSATION;
240 }
241 }
242 //Default values for frequency min and max
243 int hMaterialId = AddParametricEffect(
244 _amplitude, _amplitude != null ? _amplitude.Length : 0,
245 _pitch, _pitch != null ? _pitch.Length : 0,
246 _freqMin, _freqMax,
247 _transient, _transient != null ? _transient.Length : 0,
248 _loops > 0
249 );
250 if (hMaterialId == -1)
251 {
252 DebugAPIMode("PlayParametricHapticEffect: Failed to create parametric effect.");
253 return;
254 }
255
256 List<CommandData> targets = new List<CommandData> { new CommandData(Operator.Plus, GroupID.Palm, _controllerSide) };
257 AddTargetToEvent(hMaterialId, targets);
258 SetEventIntensity(hMaterialId, _intensity);
259 DebugAPIMode("PlayParametricHapticEffect: Event played at " + Time.realtimeSinceStartup);
260 double vibrationLength = GetVibrationLength(hMaterialId); // Obtain the duration of the effect
261#if (UNITY_ANDROID && !ENABLE_METAQUEST && !ENABLE_OPENXR && !UNITY_EDITOR) || UNITY_IOS
262 MobileControl.EnqueueEffect(hMaterialId, vibrationLength, _loops, _intensity);
263#else
264 HAR.PlayEvent(hMaterialId, (double)-Time.realtimeSinceStartup, 0, 0);
265#endif
266 }
267
279 public static void PlayAdvanced(double[] _amplitude, double[] _pitch, double _freqMin = DEFAULT_FREQ_MIN, double _freqMax = DEFAULT_FREQ_MAX, double[] _transient = null, double _intensity = DEFAULT_INTENSITY, int _loops = DEFAULT_LOOPS, LateralFlag _controllerSide = DEFAULT_CONTROLLER_SIDE)
280 {
281 PlayParametricHapticEffect(_amplitude, _pitch, _freqMin, _freqMax, _transient, _intensity, _loops, _controllerSide);
282 }
283
292 public static void Play(double[] amplitudes, double[] transients, double _intensity = DEFAULT_INTENSITY, int _loops = DEFAULT_LOOPS, LateralFlag _controllerSide = DEFAULT_CONTROLLER_SIDE)
293 {
294 DebugAPIMode("PlayAmplitudesTransients: Playing amplitudes and transients at " + Time.realtimeSinceStartup);
295
296 PlayAdvanced(
297 amplitudes, // The amplitude array
298 null, // No pitch
299 DEFAULT_FREQ_MIN, // Default frequency min
300 DEFAULT_FREQ_MAX, // Default frequency max
301 transients, // The transient triplets
302 _intensity, // Intensity of the effects
303 _loops, // Number of loops
304 _controllerSide // Controller side
305 );
306 }
307
314 public static void Play(double[] amplitudes, double _intensity = DEFAULT_INTENSITY, int _loops = DEFAULT_LOOPS, LateralFlag _controllerSide = DEFAULT_CONTROLLER_SIDE)
315 {
316 DebugAPIMode("Play: Playing amplitudes at " + Time.realtimeSinceStartup);
317
318 Play(
319 amplitudes, // The amplitude array
320 null, // No transients
321 _intensity, // Intensity of the effects
322 _loops, // Number of loops
323 _controllerSide // Controller side
324 );
325 }
326
338 public static void PlayTransients(double[] transients, double _intensity = DEFAULT_INTENSITY, int _loops = DEFAULT_LOOPS, LateralFlag _controllerSide = DEFAULT_CONTROLLER_SIDE)
339 {
340 // Debug message with timestamp for when the transients play
341 DebugAPIMode("PlayTransients: Playing transients at " + Time.realtimeSinceStartup);
342 // This call should include only the transient array, as we're only interested in playing transients.
343 PlayAdvanced(
344 null, // No amplitude
345 null, // No pitch
346 DEFAULT_FREQ_MIN, // Default frequency min
347 DEFAULT_FREQ_MAX, // Default frequency max
348 transients, // The transient triplets
349 _intensity, // Intensity of the transient effects
350 _loops, // Number of loops
351 _controllerSide // Controller side
352 );
353 }
354
362 public static void PlayTransient(double time = DELAY_COMPENSATION, double amplitude = 1.0, double frequency = 1.0, double _intensity = DEFAULT_INTENSITY, int _loops = DEFAULT_LOOPS, LateralFlag _controllerSide = DEFAULT_CONTROLLER_SIDE)
363 {
364 DebugAPIMode("PlayTransient: Playing transient at " + Time.realtimeSinceStartup);
365 double[] transient = { time, amplitude, frequency };
366 // Call the PlayParametricHapticEffect coroutine with the transient parameters
367 PlayTransients(
368 transient, // The transient parameters
369 _intensity,
370 _loops, // intensity and loops optional
371 _controllerSide
372 );
373 }
374
380 public static void PlayConstant(double amplitude, double time, double _intensity = DEFAULT_INTENSITY, int _loops = DEFAULT_LOOPS, LateralFlag _controllerSide = DEFAULT_CONTROLLER_SIDE)
381 {
382 double[] amplitudes = { 0.0, amplitude, time, amplitude };
383 Play(amplitudes, _intensity, _loops, _controllerSide);
384 }
385
386 private static int AndroidVersion
387 {
388 get
389 {
390 using (var version = new AndroidJavaClass("android.os.Build$VERSION"))
391 {
392 return version.GetStatic<int>("SDK_INT");
393 }
394 }
395 }
396 public static void MobileCancelHaptics()
397 {
398#if (UNITY_ANDROID && !ENABLE_METAQUEST && !ENABLE_OPENXR && !UNITY_EDITOR) || UNITY_IOS
399 MobileControl.StopEffects();
400#endif
401 HAR.StopAllEvents();
402 //stopHapticEffect = true; // Set the stopHapticEffect flag to true
403 }
404
408 private static void StopPreviousHapticEffect()
409 {
410#if (UNITY_ANDROID && !ENABLE_METAQUEST && !ENABLE_OPENXR && !UNITY_EDITOR) || UNITY_IOS
411 MobileCancelHaptics();
412 // Set the stopHapticEffect flag to true
413 stopHapticEffect = true;
414#else
415 HAR.StopAllEvents();
416#endif
417 }
418
422 public static void StopCurrentHapticEffect(int hapticMaterialId)
423 {
424#if (UNITY_ANDROID && !ENABLE_METAQUEST && !ENABLE_OPENXR && !UNITY_EDITOR) || UNITY_IOS
425 MobileCancelHaptics();
426#else
427 HAR.StopEvent(hapticMaterialId);
428#endif
429 }
430 }
431}
Represents a haptic material, which is a ScriptableObject in Unity. This class is used to handle hapt...
string text
Publicly accessible property to get the haptic data text.
GroupID
Enumeration for group identification in haptic command data.
Operator
Enumeration for operator signs in haptic command data.
LateralFlag
Enumeration for lateral flag in haptic command data.
Structure for command data in haptic systems.