SALE ENDS TODAY: Save 50% on all Swift books and bundles! >>

How to modify haptic events over time using CHHapticParameterCurve

Swift version: 5.1

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.

SPONSORED Instabug helps you identify and resolve severe crashes quickly. You can retrace in-app events and know exactly which line of code caused the crash along with environment details, network logs, repro steps, and the session profiler. Ask more questions or keep users up-to-date with in-app replies straight from your dashboard. Instabug takes data privacy seriously, so no one sees your data but you! See more detailed features comparison and try Instabug's crash reporting SDK for free.

Save 50% on all books and bundles

The biggest ever Hacking with Swift sale is now on, letting you save 50% on all books and bundles. Learn something new with Swift and enjoy great savings while the sale lasts!

Click here to save 50% in our Black Friday sale!

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 Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift (Vapor Edition) 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 Server-Side Swift (Kitura Edition) Buy Beyond Code

Was this page useful? Let us know!

Average rating: 4.0/5