UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

How to modify haptic events over time using CHHapticParameterCurve

Swift version: 5.6

Paul Hudson    @twostraws   

Core Haptics gives us extraordinary control over vibration events, including one-off taps (transient haptics), longer vibrations (continuous haptics), and shaped vibrations (haptic parameter curves).

For example, if you wanted to make a vibration that started strong and faded away, you would use import CoreHaptics and create a property to store the haptic engine:

var engine: CHHapticEngine?

Then you would spin up the haptic engine like this:

guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else { return }

do {
    engine = try CHHapticEngine()
    try engine?.start()
} catch {
    print("There was an error creating the engine: \(error.localizedDescription)")
}

Finally, you need to run this code whenever you want your haptic to play

// create a dull, strong haptic
let sharpness = CHHapticEventParameter(parameterID: .hapticSharpness, value: 0)
let intensity = CHHapticEventParameter(parameterID: .hapticIntensity, value: 1)

// create a curve that fades from 1 to 0 over one second
let start = CHHapticParameterCurve.ControlPoint(relativeTime: 0, value: 1)
let end = CHHapticParameterCurve.ControlPoint(relativeTime: 1, value: 0)

// use that curve to control the haptic strength
let parameter = CHHapticParameterCurve(parameterID: .hapticIntensityControl, controlPoints: [start, end], relativeTime: 0)

// create a continuous haptic event starting immediately and lasting one second
let event = CHHapticEvent(eventType: .hapticContinuous, parameters: [sharpness, intensity], relativeTime: 0, duration: 1)

// now attempt to play the haptic, with our fading parameter
do {
    let pattern = try CHHapticPattern(events: [event], parameterCurves: [parameter])

    let player = try engine?.makePlayer(with: pattern)
    try player?.start(atTime: 0)
} catch {
    // add your own meaningful error handling here!
    print(error.localizedDescription)
}

As you can see, it does take quite a bit of code to get a fairly basic effect. However, the reason for that is because Core Haptics allows us to create more complicated effects by adding more parameters, curves, and events – it’s a remarkably flexible API.

For example, we just created a fading continuous haptic, but we can actually combine that with multiple transient haptics to make an explosion effect: one fading buzz, with lots of smaller little pops going off at the same time.

To try this out, first make sure you follow the setup steps above, then use this code to create and play your haptic:

var events = [CHHapticEvent]()
var curves = [CHHapticParameterCurve]()

do {
    // create one continuous buzz that fades out
    let sharpness = CHHapticEventParameter(parameterID: .hapticSharpness, value: 0)
    let intensity = CHHapticEventParameter(parameterID: .hapticIntensity, value: 1)

    let start = CHHapticParameterCurve.ControlPoint(relativeTime: 0, value: 1)
    let end = CHHapticParameterCurve.ControlPoint(relativeTime: 1.5, value: 0)

    let parameter = CHHapticParameterCurve(parameterID: .hapticIntensityControl, controlPoints: [start, end], relativeTime: 0)
    let event = CHHapticEvent(eventType: .hapticContinuous, parameters: [sharpness, intensity], relativeTime: 0, duration: 1.5)
    events.append(event)
    curves.append(parameter)
}

for _ in 1...16 {
    // make some sparkles
    let sharpness = CHHapticEventParameter(parameterID: .hapticSharpness, value: 1)
    let intensity = CHHapticEventParameter(parameterID: .hapticIntensity, value: 1)
    let event = CHHapticEvent(eventType: .hapticTransient, parameters: [sharpness, intensity], relativeTime: TimeInterval.random(in: 0.1...1))
    events.append(event)
}

do {
    let pattern = try CHHapticPattern(events: events, parameterCurves: curves)

    let player = try engine?.makePlayer(with: pattern)
    try player?.start(atTime: 0)
} catch {
    print(error.localizedDescription)
}

By combining 16 random transient haptics with our fading continuous haptic, we can get an effect that feels great and can be bundled into a method for easier re-use – it’s a really neat special effect you can add to both apps and games.

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

Sponsor Hacking with Swift and reach the world's largest Swift community!

Available from iOS 13.0

Similar solutions…

About the Swift Knowledge Base

This is part of the Swift Knowledge Base, a free, searchable collection of solutions for common iOS questions.

BUY OUR BOOKS
Buy Pro Swift Buy Pro SwiftUI Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

Average rating: 4.0/5

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.