最高の振動をデザインするための下準備〜UnityからCore Haptic FrameWorkを使ってみた〜

#はじめに
この記事は「[サムザップ #1 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/sumzap1)」の12月7日の記事です。
昨日の記事は@KoniroIrisさんの「【Unity】アップデートされたTerrainでトンネルを掘ろう！」でした。

今回は、iOS13で新しく追加されたCore Haptic FrameWorkをUnityを使って、iPhoneの振動生成を試行錯誤するツールを作ったので、その紹介をします。

#振動作成を試行錯誤ためのツール
振動作成するためのUnityで下記のようなツールを用意しました。
![Screen Shot 2020-12-07 at 16.23.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249963/9b1b202c-831f-8ac5-6c92-1ab6fb5b4140.png)
このツールでできること
①強さの調整
②鋭さの調整
③始まりと終わりの強さと鋭さを設定し、徐々に振動を変化させる
④SOSを表現したサンプルの実行
パラメータを調整しながら、自分の表現したい振動を見つけることを目的としています。

#背景
私はよく通勤時間や隙間時間を使って、よくカジュアルゲームで遊びます。
カジュアルゲームをやっていて良く感じることは、ゲーム中の振動が心地いいということです。
ゲーム内容ではなく、またあの振動に触れたいと思い、ゲームをプレイしてしまうことがしばしばあります。
通勤中など、マナー音をゲームする人が多く、振動は重要なゲーム演出の一つだと言えます。
自分でこの振動をデザインしてみたいなと思い、Core Haptic FrameWorkを使って、上記のようなツールを用意しました。

#Core Haptic FrameWork
Core Haptic FrameWorkはiOS13で新しく追加されたフレームワークです。
詳しくは[公式のドキュメント](https://developer.apple.com/documentation/corehaptics)をご覧ください。
このFrameWorkをUnityで呼び出し、振動生成のツールの実装しています。

以前までは下記のようにAppleがあらかじめ用意されたものから好みのものを選択し、振動を表現していました。

```obj-c:以前までの振動の呼び出し
extern"C"voidplaySystemSound (int n) 
{
    AudioServicesPlaySystemSound(n);
}
```

Core Haptic FrameWorkではユーザーが独自に振動を作れるようになりました。
それぞれ強さ、鋭さ、長さ、遅延時間などが設定できます。

```swift:強さ、鋭さ、遅延時間を指定して、振動を呼び出し（ツールの強さの調整、鋭さの調整に使用）
func createHapticEvents() -> [CHHapticEvent] 
{
    let intensity = CHHapticEventParameter(parameterID: .hapticIntensity, value: 1) 
    let sharpness = CHHapticEventParameter(parameterID: .hapticSharpness, value: 1)
    let event = CHHapticEvent(eventType: .hapticTransient, parameters: [intensity, 	sharpness], relativeTime: 0)
	return [event]
}
```

最初と最後の振動の強さ、鋭さを指定し、どれぐらいずつ振動を変化させるかを指定し、徐々に変化する振動を作ることができます。

```swift:fromからtoへと徐々に強さと鋭さを変更していく（ツールの【始まりと終わりの強さと鋭さを設定し、徐々に振動を変化させる】で使用）
func createHapticEvents() -> [CHHapticEvent] {
    var events: [CHHapticEvent] = []
    for i in stride(from: 0, to: 1, by: 0.1) {
        let intensity = CHHapticEventParameter(parameterID: .hapticIntensity, value: Float(1 - i)) 
        let sharpness = CHHapticEventParameter(parameterID: .hapticSharpness, value: Float(1 - i))
        let event = CHHapticEvent(eventType: .hapticTransient, parameters: [intensity, sharpness], relativeTime: i)
        events.append(event)
    }	
    return events
}
```

最後により細かく設定する例になります。[イベントタイプ](https://developer.apple.com/documentation/corehaptics/chhapticevent/eventtype)、発生タイミングを設定することができます。

```swift:eventTypeと振動の継続時間を細かく設定（ツールのSOSサンプルで使用）
func createHapticEvents() -> [CHHapticEvent] {
    let short1 = CHHapticEvent(eventType: .hapticTransient, parameters: [], relativeTime: 0)
    let short2 = CHHapticEvent(eventType: .hapticTransient, parameters: [], relativeTime: 0.2)
    let short3 = CHHapticEvent(eventType: .hapticTransient, parameters: [], relativeTime: 0.4)
    let long1 = CHHapticEvent(eventType: .hapticContinuous, parameters: [], relativeTime: 0.6, duration: 0.5) 
    let long2 = CHHapticEvent(eventType: .hapticContinuous, parameters: [], relativeTime: 1.2, duration: 0.5) 
    let long3 = CHHapticEvent(eventType: .hapticContinuous, parameters: [], relativeTime: 1.8, duration: 0.5)
    let short4 = CHHapticEvent(eventType: .hapticTransient, parameters: [], relativeTime: 2.4) 
    let short5 = CHHapticEvent(eventType: .hapticTransient, parameters: [], relativeTime: 2.6) 
    let short6 = CHHapticEvent(eventType: .hapticTransient, parameters: [], relativeTime: 2.8)
    
    return [short1, short2, short3, long1, long2, long3, short4, short5, short6]
}
```

#まとめ
今回はUnityからCore Haptic FrameWorkを呼び出し、振動を試行錯誤するためのツールの紹介しました。
ただツールを使って、振動を調整してきましたが、まだまだ自分の思った通りの振動を表現することはできていません。
デザイナーさんが色を見て、その色をだいたいの構成するRGB値を予想できるように、振動をデザインできるようになれたらと考えています。
明日はアドベントカレンダーの担当は@kurosawa_tomokazuさんです。