AppleWatchKitとSpriteKitでスペースシューティングゲームを作ってみた

# はじめに
こんにちは:leaves:
私は個人的に**SpriteKit**が好きで、**WatchKit**の練習と**タッチイベント**の確認のためにAppleWatch上で動く、簡単なゲームを作ってみたので共有したいと思います(ゲームが面白くないのは秘密です...)

![sample.gif](https://qiita-image-store.s3.amazonaws.com/0/128250/1ff76e70-98e2-7d06-f34f-83f13cc9b40a.gif) <img width="155" alt="Target.png" src="https://qiita-image-store.s3.amazonaws.com/0/128250/c63f5536-3728-e721-8c61-ee0934eac1b3.png">

https://github.com/KikurageChan/TimeCosmos

# ゲームについて
**272px × 340px**ととても小さな画面でのスワイプ動作はやりにくく、UIデザイン的にも問題があるかもしれないので、操作をタップのみにしたり、AppleWatchの横についているネジ(**Digital Crown**)を利用する方が良かったかもしれません...

# 実装について
プロジェクトの作成方法などはこちらが大変参考になりました
[Apple WatchでSpriteKitを使ってアニメーション ワンダープラネットブログ](http://developer.wonderpla.net/entry/blog/engineer/SpriteKit_with_watchOS3/)

WKInterfaceControllerなどを用意してしまえば、通常のSpriteKitでゲームを作る時と、そんなに変わらないと感じました。

自動生成される.sksファイルのシーンのアンカーポイントがデフォルトで中心になっているので、左下(x: 0, y: 0)に変更しておきます。

# AppleWatchの画面サイズについて
**ステータスバーを除いた**コンテンツの領域は**WKInterfaceController**内の[contentFrame](https://developer.apple.com/reference/watchkit/wkinterfacecontroller/1619525-contentframe)プロパティで取得できます

![Screen.png](https://qiita-image-store.s3.amazonaws.com/0/128250/0d92d8d9-408a-a5c1-e384-0a3ce9e776a6.png)

このサイズに合わせてGameScene.sksなどのシーンのサイズを調節すると、
画面が見やすくて良い感じです。

# AppleWatchのタッチイベントについて
**AppleWatch**は**UIKit**の概要とは異なっていて、**UIView**を利用することができません。
よって、UIViewなどが持つタッチイベントを取得する`UIResponder`のメソッドが利用できないのです。

```swift
//利用できないメソッドたち
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {}
```

そこで別の方法として、**UIView**の`UITapGestureRecognizer`のようなジェスチャーを利用してタッチイベントを取得することができるようです。([UIViewの座標とSKNodeの座標の違い](http://qiita.com/shoaooki/items/954406cb5a26927b33a4)に気をつけます)

- **WKLongPressGestureRecognizer**の`minimumPressDuration = 0`に設定(TouchBeganStateをすぐに取得するため)
- ロングタップ時のメソッドを定義(今回はIB接続)
- [location(ofTouch: in :)](https://developer.apple.com/reference/uikit/uigesturerecognizer/1624201-location)が利用できないので、座標計算するExtensionを追加

```swift
@IBAction func longTap(_ sender: WKLongPressGestureRecognizer) {
    let point = sender.locationInView()
    switch sender.state {
    case .began:
        print("touchBegan:\(point)")
    case .changed:
        print("touchMoved:\(point)")
    case .ended:
        print("touchEnded:\(point)")
    default: break
    }
}

extension WKGestureRecognizer {
    //シーンのアンカーポイントはデフォルトの(x: 0, y: 0)を利用
    func locationInView() -> CGPoint {
        let location = locationInObject()
        let bounds = objectBounds()
        return CGPoint(x: location.x, y: bounds.maxY - location.y)
    }
}
```

これでAppleWatch×SpriteKitのタッチ座標を取得することでノードをドラッグできるようになりました。

![touch.gif](https://qiita-image-store.s3.amazonaws.com/0/128250/97318334-0f11-797d-eafa-ba360f5fe453.gif)

# おわりに
**AppleWatch**のゲームは画面が小さく、操作のための領域を取ると、ゲーム画面が減ってしまうので、UIとの兼ね合いが難しいと感じました。
また、AppleWatchの**TouchEvent**で悩んでいたのですが、この機会にまとめることができて良かったです。


# 参考にさせていただいた記事
- [WatchKit プログラミングガイド Apple](https://developer.apple.com/jp/documentation/General/Conceptual/WatchKitProgrammingGuide/)

- [UIGestureRecognizer の種類 Qiita](http://qiita.com/taketomato/items/e0e45f0d768109abef2f)

見て頂いてありがとうございます。