Last active
March 20, 2026 09:38
-
-
Save HofiOne/daf15897cf565e28315437728bce8b98 to your computer and use it in GitHub Desktop.
Native iOS, tvOS vibration of the first available controller
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #if TARGET_OS_IOS || TARGET_OS_TV | |
| static CHHapticEngine* cachedHapticEngine = nil; | |
| static GCController* cachedController = nil; | |
| bool Native_VibrateController(float intensity, float duration) | |
| { | |
| // Clamp input | |
| intensity = fmaxf(0.0f, fminf(intensity, 1.0f)); | |
| duration = fmaxf(0.02f, duration); | |
| // Vibrate game controllers (iOS 14+ and tvOS 14+) | |
| if (@available(iOS 14.0, tvOS 14.0,*)) { | |
| NSArray<GCController*>* controllers = [GCController controllers]; | |
| // Use first available controller only | |
| if (controllers.count == 0) | |
| return NO; | |
| GCController* controller = controllers[0]; | |
| if (controller.haptics) { | |
| // Check if we need to recreate engine (controller changed or engine invalid) | |
| if (cachedController != controller || cachedHapticEngine == nil) { | |
| cachedController = nil; | |
| // Clean up old engine | |
| if (cachedHapticEngine) { | |
| [cachedHapticEngine stopWithCompletionHandler:nil]; | |
| cachedHapticEngine = nil; | |
| } | |
| // Get first supported locality | |
| NSSet<GCHapticsLocality>* localities = controller.haptics.supportedLocalities; | |
| if (localities.count > 0) { | |
| GCHapticsLocality locality = [localities anyObject]; | |
| // Create and cache new engine | |
| cachedHapticEngine = [controller.haptics createEngineWithLocality:locality]; | |
| if (!cachedHapticEngine) { | |
| NSLog(@"Error creating haptic engine"); | |
| return NO; | |
| } | |
| cachedController = controller; | |
| NSError* error = nil; | |
| [cachedHapticEngine startAndReturnError:&error]; | |
| if (error) { | |
| NSLog(@"Error starting haptic engine: %@", error.localizedDescription); | |
| cachedHapticEngine = nil; | |
| cachedController = nil; | |
| return NO; | |
| } | |
| } | |
| } | |
| // Use cached engine if available | |
| if (cachedHapticEngine) { | |
| NSError* error = nil; | |
| // Create haptic event (this is relatively cheap) | |
| CHHapticEvent* event = [[CHHapticEvent alloc] initWithEventType:CHHapticEventTypeHapticContinuous | |
| parameters:@[ | |
| [[CHHapticEventParameter alloc] initWithParameterID:CHHapticEventParameterIDHapticIntensity value:intensity], | |
| [[CHHapticEventParameter alloc] initWithParameterID:CHHapticEventParameterIDHapticSharpness value:0.5] | |
| ] | |
| relativeTime:0 | |
| duration:duration]; | |
| CHHapticPattern* pattern = [[CHHapticPattern alloc] initWithEvents:@[event] parameters:@[] error:&error]; | |
| if (!error) { | |
| id<CHHapticPatternPlayer> player = [cachedHapticEngine createPlayerWithPattern:pattern error:&error]; | |
| if (!error) | |
| [player startAtTime:0 error:&error]; | |
| } | |
| if (error) | |
| NSLog(@"Error playing haptic pattern: %@", error.localizedDescription); | |
| else | |
| return YES; | |
| } | |
| } | |
| } | |
| return NO; | |
| } | |
| #endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment