【Watch OS】AppleWatch向けDDRハイスピ計算機を作ってみた

  • 概要

Dance Dance Revolution(以下DDR)のハイスピード機能(以下HS)は、選曲前に「BPM×HS倍率=プレイヤーの適性スクロールスピード(以下SS)」をプレイヤー自身が計算し設定するシステムである。基本的には暗記もしくは暗算が必要となるが、キリの良いBPMならばともかく、疲労感の強い状況でキリの悪いBPMのHS倍率を計算するのは正直しんどいというのがプレイヤーとしての本音である。(236BPMのHS倍率に迷ったりする)

そこで、快適なHS調整を目的としたApple Watch向けHS計算機を作成する。

f:id:skty001:20200928163442p:plain

 

 

 

  • 開発環境

PC:MacBook Pro (13-inch, 2017, Two Thunderbolt 3 ports)

OS:macOS Catalina 10.15.7

IDEXcode 12.0.1(12A7300)

言語:Swift

FW:SwiftUI

github.com

 

  • 本アプリを作る上で考えたこと

  1. Apple Watchの小さい画面をポチポチするようなモノにしたくないので、Digital Crownをメインとした操作とする。
  2. 適性SSピッタリのHS倍率にならない場合を考慮し、目標SS以下HS倍率・目標SS以上HS倍率の2通りのHS倍率を表示する。 

 

  • 画面レイアウト

下記画像は、本アプリをシミュレータ(Apple Watch Series 6 44mm)で動かしたもののスクリーンショットである。

f:id:skty001:20200928163446p:plain f:id:skty001:20200928164214p:plain f:id:skty001:20200928163647p:plain

  1. 楽曲BPM・目標SSをタップすると文字色が青になり、DigitalCrownで設定ができるようになる。目標SSはプレイヤーごとに殆ど決まった値になるためタッチ操作を許すこととした。
  2. 楽曲BPMの最大値はTohoku EVOLVEDのラストを想定して1040とし、それに伴い目標SSの最大値は1040×8=8320とした。
  3. 画面下部(青い線の下)には、楽曲BPMと目標SSから算出したHS倍率と実際の計算結果を表示する。上のHS倍率は目標SS以下で最も大きいHS倍率、下のHS倍率は目標SS以上で最も小さいHS倍率となる。

 

  • 今後の目標

  1. 段位認定やコースでの使用を想定して、4曲分のHS倍率を保存して表示する機能を実装する。HS倍率計算画面とは別に保存HS倍率表示画面を専用に作る感じになると思う。
  2. 心拍数を表示する機能を実装する。現在の心拍数に加え、1曲2分として3分間の最大心拍数、平均心拍数を表示する。できればHS倍率計算画面・保存HS倍率表示画面の下部に表示したい。
  3. DigitalCrownでの値設定において細かい操作が難しい問題があるため、操作性の向上を考える。オプションとしてテンキーでの入力に対応するかもしれない。できれば〜できれば〜HS倍率計算画面を表示したままで音声入力できたら楽だよね〜…雑音が多いしエラー処理も必要だしで結構大変そう。
  4. ストアに公開したい。

 

  • 技術的なこと

  •  Digital Crownの状態取得について

以下はDigital Cronwの状態を取得するメソッド digitalCrownRotation()のリファレンス。

developer.apple.com


 

 以下は、digitalCrownRotation()の定義。

func digitalCrownRotation<V>(_ bindingBinding<V>, from minValue: V, through maxValue: V, by stride: V.Stride? = nil, sensitivityDigitalCrownRotationalSensitivity = .high, isContinuousBool = false, isHapticFeedbackEnabledBool = true) -> some View where V : BinaryFloatingPoint, V.Stride : BinaryFloatingPoint

このなかで今回使用及び検証したものについて説明する。(採用は太文字)

 

  • _ binding: Binding<V>

DigitalCrownが回転したとき値の増減(更新)を行う変数を指定。

  • from minValue: V

値が取り得る最小値を指定。

  • through maxValue: V

値が取り得る最大値を指定

  • by stride: V.Stride? = nil

値の刻み幅を指定。1と指定すれば1刻みで値が増減する。

  • sensitivity: DigitalCrownRotationalSensitivity = .high

minValueとmaxValueの間を移動する速さ(DigitalCrownの感度)。.high, .medium, .lowから指定。指定なしの場合true。

  • isContinuous: Bool = false

minValueとmaxValueの間を繋げるか否か。trueの場合、minValueを下回った時にmaxValueになり、maxValueを上回った時にminValueになる。指定なしの場合false。

  • isHapticFeedbackEnabled: Bool = true) -> some View where V : BinaryFloatingPoint

DigitalCrownを回しているとき触覚フィードバック(ブルブル震える)を発生するか否か。指定なしの場合true。

 

 本アプリから楽曲BPMを表示するコードを抜粋し、シンプルにしたもの。

■sample.swift

struct ContentView: View {
    @State var inputBPM : Double = 440
    // 中略
    var body: some View {
    // 中略
        Text(String(Int(inputBPM))
.digitalCrownRotation($inputBPM, from:0, through:1040, by:1) //中略 } }

本テキストボックスは楽曲BPMを格納している変数inputBPMの値を表示する。

inputBPMの値をDigitalCrownの回転で制御するため、inputBPM自身と楽曲BPMが必要とする値範囲をdigitalCrownRotationの引数で指定している。

  • 値を増減させたいのはinputBPMなので_ binding:には$inputBPMを指定。このとき$をつけて参照渡しにしなければならない。
  • inputBPMの取り得る最小値・最大値として、from minValue:には0を、through maxValue:には1040を指定。
  • inputBPMは小数を取らず1刻みの整数となるためby stride:には1を指定。

これで、DigitalCrownを回したときinputBPMの値が更新される。inputBPMには@Stateがついているため、更新に伴いContentViewが再描画され、更新後の値が表示される。

実際はinputBPMの値をHS倍率を計算する関数に渡し、それらもまとめて計算しているが、inputBPMが更新され再描画されることには変わりない。

  • ただの感想

ここからは業務でC言語を主に用いているプログラマが、Swift/SwiftUI等を20時間ほど触ってみて感じたことの覚書。

普段、それっぽいワードを使わないので変な使い方してたら...すみません

  1. 【SwiftUI】UIのプレビュー機能(デザインキャンバスのダイナミックリプレースメント?)がすごく便利。UIを弄ると即座にビルドされプレビューが更新されるため、シミュレータを動かさずともUIが確認できる。
  2. 【SwiftUI】View作成はコードベース。Windowsフォームアプリ等で見られる、フォームにボタンやテキストボックス等を設置して、それぞれの動作を設定していくものではない。が、それはコードかGUIかの違いであり、UIレイアウトの知識は必要。
  3. 【SwiftUI】SwiftUIのViewは@Stateをつけた変数の値が変化するたびに更新される。基本的には外部のセンサやButtonタッチ時のaction等で値が変化することを想定している?多分ViewとControllerの分離というやつで、ViewのBody内で値の代入等の計算はできないっぽいので、@Stateをつけた変数を自作の関数に渡し、戻り値を画面表示等に用いるようにした。
  4. 【Swift】他言語の貯金があるのでSwift自体にはそれほど苦労しなかった。とはいえちゃんと勉強する必要があるな〜とは常々。
  5. XcodeXcodeのバージョンとビルドできるiOS/WatchOS/etc...のバージョンが決まっているのが驚きだった。AndroidなんかだとSDKだけ引っ張ってくれば良いのかな?よく考えてみれば当たり前だけども...。Xcodeの過去バージョンはAppleが配布している(https://developer.apple.com/download/more/)
  6. 【AppID】アプリと紐づくID。発行上限は一週間で10個。
  7. 【実機デバッグ】AppleWatch向けアプリを実機で動かすには、AppleWatchとペアリングしたiPhoneMacに接続する必要がある。iPhoneからAppleWatchにぶん投げる感じ。Apple製品が3つ必要とはたまげたなぁ。

 

  • 感想

約5年ぶりのスマートデバイス向けアプリの開発だった。普段日常的に触れているデバイスで自分の作ったものが動作するのは嬉しみが溢れる。基本的に全部自分で用意する組み込み系と違い、OS側で用意されているものを如何に使うか?みたいなところが焦点になってるのかな〜?なんて感じた。

普段使っている言語etcとは全く別のものを使って何かを作ってみるのは、普段と別の脳を使っている感じでやりがいがあるな!でも別に普段の経験が無かというとそうでもないのが面白い。

今後の目標に挙げたものを達成していきまぁす!ストア公開までやり切って、他のDDRプレイヤーが使ってたら嬉しい。若干ニッチだけど!