10分で理解するSpriteKit

# [SpriteKit](https://developer.apple.com/documentation/spritekit) とは
Apple が提供している2Dのゲームを作るためのフレームワークです
アニメーションや物理シミュレーションを使ったゲームが簡単に実装できます

この他にも本格的なゲーム開発では以下のようなフレームワークが使われるようです
[Cocos2d-x](http://www.cocos2d-x.org/)
[Unity](https://unity3d.com/jp)
[Unreal Engine](https://www.unrealengine.com/ja/what-is-unreal-engine-4)

SpriteKit は学習コストが低くとりあえずシンプルなゲームを作るには十分な機能を備えています

# TL;DR
- 画面に遷移した時は `didMove` 、タップした時は `touchDown` が呼び出される
- `.sks` ファイルは `.storyboard` みたいなもの
- 表示要素は `ノード` と呼ばれる
- 物理演算は `SKPhysicsBody` 、アニメーションなどの動きは `SKAction` がいい感じに処理してくれる

# SpriteKit を利用したゲームの作り方
## Xcode のプロジェクトを作る
Xcode で新規プロジェクトを作成する時に "Game" を選択します
![1.png](https://qiita-image-store.s3.amazonaws.com/0/43699/18544656-6fc8-34dd-2aa6-8ad20a7d33d7.png)

"Game Technology" に "SpriteKit" を選択します
※デフォルトで SpriteKit が選択されています
![4.png](https://qiita-image-store.s3.amazonaws.com/0/43699/eba5abf4-1213-76ea-6739-5bdebe473b56.png)

これでベースが作成されます
![2.png](https://qiita-image-store.s3.amazonaws.com/0/43699/472d11d0-74a8-355c-9d5f-d16030bff6fc.png)

## とりあえず実行してみる
プロジェクトを新規作成した状態から何も変えずにとりあえず実行してみましょう
めちゃくちゃシンプルなサンプルコード的なものが自動で作成されているので、以下のようなアプリが起動するはずです

![spritekit.gif](https://qiita-image-store.s3.amazonaws.com/0/43699/cdf705d1-8e25-c7b4-0c80-5550068434f9.gif)

画面をタップすると `Hello, World!` の文字が小さくなって、タップした位置に四角が表示されます
画面に触れたまま動かすと四角が追従して動くというものです

## ソースコードを見てみる
画面をタップした時にどんな処理が実行されているかを見て見ましょう

先ほどのアニメーションの処理は `GameScene.swift` の中に書かれています
まず、画面をタップした時には `touchesBegan` が呼び出されます
これは SpriteKit のルールです

```swift:GameScene.swift
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let label = self.label {
            label.run(SKAction.init(named: "Pulse")!, withKey: "fadeInOut")
        }
        
        for t in touches { self.touchDown(atPoint: t.location(in: self)) }
    }
```
この中で `label.run(SKAction.init(ほげほげ)` 書かれている処理で、`Hello, World!` の文字が小さくなるアニメーションが実行されています
追従する四角を表示する処理はパッと見ここには無さそうなので `self.touchDown(ほげほげ)` の中身を見てみましょう

`touchDown` は同じファイルに書かれています

```swift:GameScene.swift
    func touchDown(atPoint pos : CGPoint) {
        if let n = self.spinnyNode?.copy() as! SKShapeNode? {
            n.position = pos
            n.strokeColor = SKColor.green
            self.addChild(n)
        }
    }
```
`self.spinnyNode` というオブジェクトをコピーして、位置と色を設定して自分の画面に追加する処理をしています
ここで、`self.spinnyNode` が何者かは同じファイルの以下の部分に書かれています

```swift:GameScene.swift
    override func didMove(to view: SKView) {
        
        // Get label node from scene and store it for use later
        self.label = self.childNode(withName: "//helloLabel") as? SKLabelNode
        if let label = self.label {
            label.alpha = 0.0
            label.run(SKAction.fadeIn(withDuration: 2.0))
        }
        
        // Create shape node to use during mouse interaction
        let w = (self.size.width + self.size.height) * 0.05
        self.spinnyNode = SKShapeNode.init(rectOf: CGSize.init(width: w, height: w), cornerRadius: w * 0.3)
        
        if let spinnyNode = self.spinnyNode {
            spinnyNode.lineWidth = 2.5
            
            spinnyNode.run(SKAction.repeatForever(SKAction.rotate(byAngle: CGFloat(Double.pi), duration: 1)))
            spinnyNode.run(SKAction.sequence([SKAction.wait(forDuration: 0.5),
                                              SKAction.fadeOut(withDuration: 0.5),
                                              SKAction.removeFromParent()]))
        }
    }
```

`didMove` はこの画面が呼び出された時に実行される処理です
これも SpriteKit のルールです
この中で `self.spinnyNode` は角が丸い四角の形に設定された `SKShapeNode` のオブジェクトがセットされていて、更にずっとクルクル回って1秒くらいしたら消えるアニメーションが定義されています
このアニメーションは `self.addChild(ほげ)` した時に画面に描画されます

## `.sks` ファイル
`label` は `Hello, World!` の文字を表示するオブジェクトで、`GameScene.sks` を開くと定義されています
`.sks` ファイルは `storyboard` と同じようなもので、画面のレイアウトをコードではなく視覚的に定義するためのファイルです
`storyboard` と同様に、これを使っても画面を作れますし使わなくてもコードから指定することで画面のレイアウトを作れます

## 全てのパーツはノード
`Hello, World!` のラベルは `SKLabelNode` クラスのオブジェクト、タップした時に表示される四角は `SKShapeNode` クラスのオブジェクトです
画面に表示されるパーツは全て `SKNode` の子クラスとなります

### 画像を表示したい時は `SKSpriteNode` を使う
別途デザインした画像をノードに表示したい場合は `SKSpriteNode` クラスを利用します
オブジェクト生成時の引数に、Assets に登録されている画像ファイル名を指定するとその画像が表示されます

```swift
let spaceship = SKSpriteNode(imageNamed: "rocket.png")
spaceship.position = CGPoint(x: 100, y: 100)
self.addChild(spaceship)
```

※コードは公式ドキュメントより引用
https://developer.apple.com/documentation/spritekit/skspritenode

### 物理演算は `SKPhysicsBody`
ノードに落下とかボールのバウンドのような物理シミュレーションを適用したい場合は、対象ノードのプロパティ `physicsBody` に `SKPhysicsBody` をセットすると物理演算を裏で勝手にやってくれます

```swift
let texturedSpaceShip = SKSpriteNode(texture: spaceShipTexture)
texturedSpaceShip.physicsBody = SKPhysicsBody(texture: spaceShipTexture,
                                              size: CGSize(width: circularSpaceShip.size.width,
                                                           height: circularSpaceShip.size.height))
```

※コードは公式ドキュメントより引用
https://developer.apple.com/documentation/spritekit/skphysicsbody

### ノードを動かしたい時は `SKAction`
`SKAction` というのがとても万能で、ノードを動かしたり、アニメーションを実行したり、音を鳴らしたり、それらのアクションを順番に実行したりと様々なことをやってくれます

# まとめ
サンプルコードの処理を元にどんな登場人物がいるのかをめちゃくちゃざっくり見ていきました
登場するクラスの数も多くないので、とりあえずゲームを作ってみるには `SpriteKit` はピッタリだと思います

公式ドキュメントにはより詳細な説明と分かりやすいサンプルコードが載っているので、開発する際にはこちらを見てみましょう
https://developer.apple.com/documentation/spritekit