IEnumerator PlayImpulsesInf(HapticPattern pattern, bool rightHand) { int i = 0; while (!pattern.stop) { pattern.loopFunc.Invoke(ref pattern, i); if (pattern.stop) { continue; } if (pattern.amplitude > 0) { Impulse(pattern.amplitude, pattern.duration, rightHand); } float waitDur = pattern.duration + pattern.waitDuration; if (waitDur <= 0) { waitDur = minWaitDur; } yield return(new WaitForSeconds(waitDur)); i++; } }
IEnumerator PlayImpulsesRepeat(HapticPattern pattern, bool rightHand) { if (pattern.repeat <= 0) { yield break; } float repeatAmount = Mathf.Clamp(pattern.repeat, 0, 1000); for (int i = 0; i < repeatAmount; i++) { pattern.loopFunc.Invoke(ref pattern, i); if (pattern.stop) { yield break; } if (pattern.repeat <= 0) { yield break; } if (pattern.amplitude > 0) { Impulse(pattern.amplitude, pattern.duration, rightHand); } float waitDur = pattern.duration + pattern.waitDuration; if (waitDur <= 0) { waitDur = minWaitDur; } yield return(new WaitForSeconds(waitDur)); } }
/// <summary> /// Begins an emanating impulse at the provided origin. /// Defaults to a simple 'hum' effect if you don't call WithEffect() /// Remember to call .Play() on the returned impulse. /// </summary> /// <param name="origin">The starting AreaFlag. Only provided a single AreaFlag pad.</param> /// <param name="depth">How many pads this will traverse before ending (will not reverb off 'end paths')</param> /// <returns>An Impulse object which can be given a HapticSequence, duration or Attenuation parameters /// Remember to call Play() on the returned object to begin the emanation /// <returns>The Impulse that you can call .Play() on to play a create a HapticHandle referencing that Haptic</returns> public static Impulse BeginEmanatingEffect(AreaFlag origin, int depth = 2) { if (depth < 0) { Debug.LogError("Depth for emanation is negative: " + depth + "\n\tThis will be clamped to 0 under the hood, negative numbers will likely do nothing"); } CreateImpulse creation = delegate(float attenuation, float totalLength, HapticSequence seq) { HapticPattern emanation = new HapticPattern(); var stages = _grapher.BFS(origin, depth); float baseStrength = 1.0f; float timeStep = totalLength / stages.Count; float time = 0.0f; for (int i = 0; i < stages.Count; i++) { AreaFlag area = AreaFlag.None; foreach (var item in stages[i]) { area |= item.Location; } if (i > 0) { baseStrength *= (1.0f - attenuation); } emanation.AddSequence(time, area, Mathf.Clamp(baseStrength, 0f, 1f), seq); time += timeStep; } return(emanation.CreateHandle().Play()); }; return(new Impulse(creation)); }
/// <summary> /// Attempts to create a haptic pattern from the provided json path /// It will create a HDF and then turn the hdf into a HapticPattern. /// </summary> /// <param name="jsonPath">Ex: StreamingAssets/Haptics/NS Demos/patterns/mech_stomp_left.pattern</param> public static HapticPattern CreatePattern(string jsonPath) { var fileName = Path.GetFileNameWithoutExtension(jsonPath); ////If we don't replace . with _, then Unity has serious trouble locating the file HapticPattern pat = null; bool isSeq = IsSequence(jsonPath); bool isPat = IsPattern(jsonPath); bool isExp = IsExperience(jsonPath); if (isPat) { pat = LoadPatternFromJson(jsonPath); pat.name = CleanName(fileName); } else if (isSeq) { Debug.LogError("Attempted to run a HapticPattern.CreateAsset while providing a sequence at path: " + jsonPath + "\n\t"); } else if (isExp) { Debug.LogError("Attempted to run a HapticPattern.CreateAsset while providing a experience at path: " + jsonPath + "\n\t"); } return(pat); }
private HapticHandle CreateHandle(SideOfHaptic side) { HapticHandle handle = null; if (TypeOfPlayable == PlayableType.Sequence) { HapticSequence seq = new HapticSequence(); seq.LoadFromAsset(PlayableResourceName); var areaFlag = side == SideOfHaptic.Left ? Where.Mirror() : Where; handle = seq.CreateHandle(areaFlag); } else if (TypeOfPlayable == PlayableType.Pattern) { HapticPattern pat = new HapticPattern(); pat.LoadFromAsset(PlayableResourceName); handle = pat.CreateHandle(); } else if (TypeOfPlayable == PlayableType.Experience) { HapticExperience exp = new HapticExperience(); exp.LoadFromAsset(PlayableResourceName); handle = exp.CreateHandle(); } else if (TypeOfPlayable == PlayableType.Impulse) { return(CreateImpulseHandle(side)); } return(handle); }
/// <summary> /// Create a HapticPattern from a HapticDefinitionFile /// </summary> /// <param name="key">Name of the root effect</param> /// <param name="hdf">A HapticDefinitionFile containing the root effect</param> /// <returns></returns> public static HapticPattern CreatePatternFromHDF(string key, HapticDefinitionFile hdf) { string cleanedKey = HapticResources.CleanName(key); if (LoadedPatterns.ContainsKey(cleanedKey)) { //Debug.Log("Pattern: " + cleanedKey + " already exists, returning it instead of needless reconstruction\n"); return(LoadedPatterns[cleanedKey].Pattern); } HapticPattern pat = ScriptableObject.CreateInstance <HapticPattern>(); var pattern_def_array = hdf.pattern_definitions[key]; foreach (var element in pattern_def_array) { //Debug.Log("Pattern Def Array: " + key + " " + element.sequence + "\n"); HapticSequence thisSeq = CreateSequenceFromHDF(element.sequence, hdf); thisSeq.name = element.sequence; ParameterizedSequence paraSeq = new ParameterizedSequence(thisSeq, element.ParseAreaFlag(), element.time, element.strength); pat.AddSequence(paraSeq); } EnsurePatternIsRemembered(cleanedKey, pat); return(pat); }
/// <summary> /// Begins a traversing impulse at the provided origin. /// Will play on pads that are the origin, destination or 'in-between' them. /// Defaults to a simple 'hum' effect if you don't call WithEffect() /// Remember to call .Play() on the returned impulse. /// </summary> /// <param name="origin">The starting AreaFlag. Only provided a single AreaFlag pad.</param> /// <param name="destination">The ending location for the traversing impulse.</param> /// <returns>The Impulse that you can call .Play() on to play a create a HapticHandle referencing that Haptic</returns> public static Impulse BeginTraversingImpulse(AreaFlag origin, AreaFlag destination) { if (!origin.IsSingleArea() || !destination.IsSingleArea()) { Debug.LogError("Invalid AreaFlag Provided: Origin is [" + origin.NumberOfAreas() + "] area(s) and Destination is [" + destination.NumberOfAreas() + "] area(s).\n\tImpulse Generator only supports single area flag values.\n"); return(null); } CreateImpulse creation = delegate(float attenuation, float totalLength, HapticSequence seq) { HapticPattern emanation = new HapticPattern(); var stages = _grapher.Dijkstras(origin, destination); float timeStep = totalLength / stages.Count; float time = 0.0f; float baseStrength = 1f; for (int i = 0; i < stages.Count; i++) { if (i > 0) { baseStrength *= (attenuation); } //Debug.Log(timeStep + "\n" + baseStrength + "\n"); emanation.AddSequence(time, stages[i].Location, Mathf.Clamp(baseStrength, 0f, 1f), seq); time += timeStep; } return(emanation.CreateHandle().Play()); }; return(new Impulse(creation)); }
/// <summary> /// Begins a traversing impulse at the provided origin. /// Will play on pads that are the origin, destination or 'in-between' them. /// Defaults to a simple 'hum' effect if you don't call WithEffect() /// Remember to call .Play() on the returned impulse. /// </summary> /// <param name="origin">The starting AreaFlag. Only provided a single AreaFlag pad.</param> /// <param name="destination">The ending location for the traversing impulse.</param> /// <returns>The Impulse that you can call .Play() on to play a create a HapticHandle referencing that Haptic</returns> public static Impulse BeginTraversingImpulse(AreaFlag origin, AreaFlag destination) { CreateImpulse creation = delegate(float attenuation, float totalLength, HapticSequence seq) { HapticPattern emanation = new HapticPattern(); var stages = _grapher.Dijkstras(origin, destination); float timeStep = totalLength / stages.Count; float time = 0.0f; float baseStrength = 1f; for (int i = 0; i < stages.Count; i++) { if (i > 0) { baseStrength *= (1.0f - attenuation); } emanation.AddSequence(time, stages[i].Location, Mathf.Clamp(baseStrength, 0f, 1f), seq); time += timeStep; } return(emanation.CreateHandle().Play()); }; return(new Impulse(creation)); }
/// <summary> /// Play the specified pattern repeatedly until StopPatternRepeat is called /// </summary> public static void PlayPatternRepeat(HapticPattern pattern, bool rightHand) { if (rightHand) { if (isRepeatingRight) { // Debug.Log("Already playing a repeating pattern on Right!"); return; } isRepeatingRight = true; } else { if (isRepeatingLeft) { // Debug.Log("Already playing a repeating pattern on Left!"); return; } isRepeatingLeft = true; } if (pattern.hapticType == HapticType.CONTINUOUS) { pattern.hapticType = HapticType.SINGLE; } Instance.PlayRepeat(pattern, rightHand); }
public static void EnsurePatternIsRemembered(string key, HapticPattern pattern) { key = HapticResources.CleanName(key); if (!LoadedPatterns.ContainsKey(key) && pattern != null) { LoadedPatterns.Add(key, new PatternImportData(pattern, key)); } }
internal static HapticPattern LoadPatternFromJson(string jsonPath) { HapticDefinitionFile hdf = LoadHDFFromJson(jsonPath); if (hdf.root_effect.type == "pattern") { var pat = CodeHapticFactory.CreatePatternFromHDF(hdf.root_effect.name, hdf); return(pat); } else { Debug.LogError("Error in LoadPatternFromJson - likely an invalid path was provided\n\t" + hdf.root_effect.name + " is of type " + hdf.root_effect.type + "\n"); return(HapticPattern.CreateNew()); //throw new InvalidOperationException("Unable to load " + hdf.root_effect.name + " as a HapticPattern because it is a " + hdf.root_effect.type); } }
IEnumerator PlayRepeatCo(HapticPattern pattern, bool rightHand) { float waitS = pattern.duration + pattern.waitDuration; if (pattern.hapticType == HapticType.REPEAT) { waitS *= pattern.repeat; } WaitForSeconds waitDur = new WaitForSeconds(waitS); while (rightHand ? isRepeatingRight : isRepeatingLeft) { Play(pattern, rightHand); yield return(waitDur); } }
/// <summary> /// Create a HapticExperience from a HapticDefinitionFile /// </summary> /// <param name="key"></param> /// <param name="hdf"></param> /// <returns></returns> public static HapticExperience CreateExperienceFromHDF(string key, HapticDefinitionFile hdf) { string cleanedKey = HapticResources.CleanName(key); HapticExperience exp = ScriptableObject.CreateInstance <HapticExperience>(); var experience_def_array = hdf.experience_definitions[key]; foreach (var element in experience_def_array) { HapticPattern thisPat = CreatePatternFromHDF(element.pattern, hdf); thisPat.name = element.pattern; ParameterizedPattern paraPat = new ParameterizedPattern(thisPat, element.time, element.strength); exp.AddPattern(paraPat); } return(exp); }
//public static NewGraphEngine _newGrapher = new NewGraphEngine(); /// <summary> /// Begins an emanating impulse at the provided origin. /// Defaults to a simple 'hum' effect if you don't call WithEffect() /// Remember to call .Play() on the returned impulse. /// </summary> /// <param name="origin">The starting AreaFlag. Only provided a single AreaFlag pad.</param> /// <param name="depth">How many pads this will traverse before ending (will not reverb off 'end paths')</param> /// <returns>An Impulse object which can be given a HapticSequence, duration or Attenuation parameters /// Remember to call Play() on the returned object to begin the emanation /// <returns>The Impulse that you can call .Play() on to play a create a HapticHandle referencing that Haptic</returns> public static Impulse BeginEmanatingEffect(AreaFlag origin, int depth = 2) { if (!origin.IsSingleArea()) { Debug.LogError("Invalid AreaFlag Provided: Origin is [" + origin.NumberOfAreas() + "] area(s).\n\tImpulse Generator only supports single area flag values.\n"); return(null); } if (depth < 0) { Debug.LogError("Depth for emanation is negative: " + depth + "\n\tThis will be clamped to 0 under the hood, negative numbers will likely do nothing"); } CreateImpulse creation = delegate(float attenuation, float totalLength, HapticSequence seq) { HapticPattern emanation = new HapticPattern(); var stages = _grapher.BFS(origin, depth); //var stages = _newGrapher.BFS(origin, depth); float baseStrength = 1.0f; float timeStep = totalLength / stages.Count; float time = 0.0f; for (int i = 0; i < stages.Count; i++) { AreaFlag area = AreaFlag.None; foreach (var item in stages[i]) { area |= item.Location; //area |= item.ConvertToAreaFlag(); } if (i > 0) { baseStrength *= (attenuation); } emanation.AddSequence(time, area, Mathf.Clamp(baseStrength, 0f, 1f), seq); time += timeStep; } return(emanation.CreateHandle().Play()); }; return(new Impulse(creation)); }
/// <summary> /// Play a haptic pattern /// </summary> /// <param name="pattern"></param> /// <param name="rightHand"></param> public static void Play(HapticPattern pattern, bool rightHand) { switch (pattern.hapticType) { case HapticType.SINGLE: Impulse(pattern.amplitude, pattern.duration, rightHand); break; case HapticType.REPEAT: Instance.StartCoroutine(Instance.PlayImpulsesRepeat(pattern, rightHand)); break; case HapticType.CONTINUOUS: Instance.StartCoroutine(Instance.PlayImpulsesInf(pattern, rightHand)); break; default: break; } }
public HapticHandle CreateCodeHaptic() { //Debug.Log("Hit\n"); HapticSequence seq = new HapticSequence(); seq.AddEffect(0.0f, new HapticEffect(Effect.Buzz, .2f)); seq.AddEffect(0.3f, new HapticEffect(Effect.Click, 0.0f)); //seq.Play(AreaFlag.All_Areas); HapticPattern pat = new HapticPattern(); pat.AddSequence(0.5f, AreaFlag.Lower_Ab_Both, seq); pat.AddSequence(1.0f, AreaFlag.Mid_Ab_Both, seq); pat.AddSequence(1.5f, AreaFlag.Upper_Ab_Both, seq); pat.AddSequence(2.0f, AreaFlag.Chest_Both, seq); pat.AddSequence(2.5f, AreaFlag.Shoulder_Both, seq); pat.AddSequence(2.5f, AreaFlag.Back_Both, seq); pat.AddSequence(3.0f, AreaFlag.Upper_Arm_Both, seq); pat.AddSequence(3.5f, AreaFlag.Forearm_Both, seq); return(pat.CreateHandle().Play()); }
public PatternImportData(HapticPattern pat, string key) { Pattern = pat; saved = false; PatternKey = key; }
public static void PlayBothHands(HapticPattern pattern) { Play(pattern, true); Play(pattern, false); }
void PlayRepeat(HapticPattern pattern, bool rightHand) { StartCoroutine(PlayRepeatCo(pattern, rightHand)); }
public static void PlayPatternRepeatBothHands(HapticPattern pattern) { PlayPatternRepeat(pattern, true); PlayPatternRepeat(pattern, false); }