SwiftUIとSpriteKitでクリスマスツリー作る

こんにちは、
オークファンAdvent Calendar 24日担当のRickyです。

19新卒として入社して半年強が経ちました。
先週人生初の日本忘年会を体験しました。

そういえば明日クリスマスですね。
この前Advent Calendar 12日の記事を書き終わったら、
うちの同期に24日の記事でなんかクリスマスに関する記事を書いてくださいよと
煽られましたから今日はSwiftUIとSpriteKitでクリスマスツリーを作りましょう。:fist:

ちなみに、
持っているMacBookAirのOSは10.14.6なのでSwiftUIのCanvasは使えない。。。。
### 環境

Xcode 11.2
Swift 5
IOS 13.2
![スクリーンショット 2019-12-22 2.00.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/78edf3e8-365b-9528-e64d-3f69e1dea6ab.png)
![スクリーンショット 2019-12-22 2.01.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/ba0f9090-f875-c6ed-9955-508bcb539b0c.png)


###流れ
１、雪背景SpriteKitParticleとイリュミネイションSpriteKitParticle作成
２、雪のUIView作成
３、クリスマスツリーUIView作成
４、ギフトUIView作成
５、文字UIView作成
６、SwiftUIのContentViewに纏める

##１、雪背景SpriteKitParticleライトイリュミネイションSpriteKitParticle作成
#### SnowParticle.sks作成 
![スクリーンショット 2019-12-22 0.50.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/97938d1b-6266-9b89-0bdd-c30d31894658.png)
![スクリーンショット 2019-12-22 0.49.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/10ae55cc-d1ba-c05b-282e-95d48a5ac3cb.png)
![スクリーンショット 2019-12-22 0.51.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/b21c62a3-d5cb-4180-98a2-22bc6de0a984.png)
![スクリーンショット 2019-12-22 2.26.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/9f2c7f97-01e5-d56c-90bf-c79d73b7698f.png)

#### StarParticle.sks作成 
![スクリーンショット 2![スクリーンショット 2019-12-22 0.51.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/cdd7da74-99e8-10f5-20c3-2be924ee1856.png)
019-12-22 0.50.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/97938d1b-6266-9b89-0bdd-c30d31894658.png)
![スクリーンショット 2019-12-22 0.49.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/10ae55cc-d1ba-c05b-282e-95d48a5ac3cb.png)
![スクリーンショット 2019-12-22 0.50.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/fb27d369-5906-fc66-3c66-04edf337d36b.png)
##### 値設定
![スクリーンショット 2019-12-22 0.51.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/94f6d092-a46b-cb91-6656-1c9b0ce163e6.png)
![スクリーンショット 2019-12-22 2.25.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/f8118a6f-3a54-71cf-b436-cd3fae4e9970.png)

#### Light1Particle.sks作成 
![スクリーンショット 2![スクリーンショット 2019-12-22 0.51.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/cdd7da74-99e8-10f5-20c3-2be924ee1856.png)
019-12-22 0.50.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/97938d1b-6266-9b89-0bdd-c30d31894658.png)
![スクリーンショット 2019-12-22 0.49.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/10ae55cc-d1ba-c05b-282e-95d48a5ac3cb.png)
![スクリーンショット 2019-12-22 0.50.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/fb27d369-5906-fc66-3c66-04edf337d36b.png)
##### 値設定

![スクリーンショット 2019-12-22 0.51.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/ff96616c-25c3-66f8-81b3-5ada06523e47.png)
![スクリーンショット 2019-12-22 2.25.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/61998286-64b0-2d8b-f517-48b86aff841e.png)

#### Light2Particle.sks作成 
![スクリーンショット 2![スクリーンショット 2019-12-22 0.51.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/cdd7da74-99e8-10f5-20c3-2be924ee1856.png)
019-12-22 0.50.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/97938d1b-6266-9b89-0bdd-c30d31894658.png)
![スクリーンショット 2019-12-22 0.49.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/10ae55cc-d1ba-c05b-282e-95d48a5ac3cb.png)
![スクリーンショット 2019-12-22 0.50.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/fb27d369-5906-fc66-3c66-04edf337d36b.png)
##### 値設定
![スクリーンショット 2019-12-22 0.51.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/568b774a-a1f0-3ee0-550a-2263dae66b95.png)
![スクリーンショット 2019-12-22 2.25.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/79b860d8-4808-34a9-c709-fe35d066991d.png)


##２、雪のUIView作成
![スクリーンショット 2019-12-22 0.50.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/1e89aa19-63c8-2b75-3c74-a87f8fe2288d.png)
![スクリーンショット 2019-12-22 1.28.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/9d7ca2a2-d75a-97d5-f10c-442bdeee6ff7.png)

```Swift:SnowBackgroundView.swift
import SwiftUI
import SpriteKit

struct SnowBackgroundView: UIViewRepresentable {
       class Coordinator: NSObject {
          var scene: SKScene?
       }
       func makeCoordinator() -> Coordinator {
           return Coordinator()
       }
       func makeUIView(context: Context) -> SKView {
           //SkView作成
           let skView = SKView()
           //FPSの表示
           skView.showsFPS = true
           //ノード数表示
           skView.showsNodeCount = true
           //シーン作成
           let scene = SKScene()
           //spriteの中心を設定する
           scene.anchorPoint = CGPoint(x: 0.5, y: 1)
           //ノードを作成
           let emitterNode = SKEmitterNode(fileNamed: "SnowParticle")
           //シーンにノード入れる
           scene.addChild(emitterNode!)
           scene.scaleMode = .resizeFill
           //シーンをこのviewの内容に設定
           context.coordinator.scene = scene
           
           return skView
       }
    
       func updateUIView(_ view: SKView, context: Context) {
           
          view.presentScene(context.coordinator.scene)
       }
}

struct SnowBackgroundView_Previews: PreviewProvider {
    static var previews: some View {
        SnowBackgroundView()
    }
}
```

### ３、クリスマスツリーUIView作成
![スクリーンショット 2019-12-22 0.50.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/1e89aa19-63c8-2b75-3c74-a87f8fe2288d.png)
![スクリーンショット 2019-12-22 1.28.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/9d7ca2a2-d75a-97d5-f10c-442bdeee6ff7.png)

```TreeView.swift
import SwiftUI
import SpriteKit

struct TreeView: UIViewRepresentable {
       class Coordinator: NSObject {var scene: SKScene?
       }
       func makeCoordinator() -> Coordinator {
           return Coordinator()
       }
       func makeUIView(context: Context) -> SKView {
           //SkView作成
           let skView = SKView()
           //シーン作成
           let scene = SKScene()
           //クリスマスてツリーノードを作成
           let treeNode = SKSpriteNode(imageNamed: "tree")
           treeNode.position = CGPoint(x: UIScreen.main.bounds.size.width/2, y: UIScreen.main.bounds.size.height/3)
           //スターノードを作成
           let starNode = SKSpriteNode(fileNamed: "StarParticle")
           starNode?.position = CGPoint(x: 0, y: treeNode.position.y-50)
           //ライトノードを作成
           let lightNode1 = SKSpriteNode(fileNamed: "Light1Particle")
           lightNode1?.position = CGPoint(x: 0, y: starNode!.position.y-120)
           let lightNode2 = SKSpriteNode(fileNamed: "Light2Particle")
           lightNode2?.position = CGPoint(x: 0, y: starNode!.position.y-200)
           //クリスマスツリーノードにスターノードとライトノードを入れる
           treeNode.addChild(starNode!)
           treeNode.addChild(lightNode1!)
           treeNode.addChild(lightNode2!)
           //シーンクリスマスツリーノードを入れる
           scene.addChild(treeNode)
           scene.scaleMode = .resizeFill
           //シーン背景色を透明で黒色にする
           scene.backgroundColor = UIColor.init(displayP3Red: 0, green: 0, blue: 0, alpha: 0.1)
           //シーンをこのviewの内容に設定
           context.coordinator.scene = scene
           return skView
       }
    
       func updateUIView(_ view: SKView, context: Context) {
          view.presentScene(context.coordinator.scene)
       }
}

struct TreeView_Previews: PreviewProvider {
    static var previews: some View {
       TreeView()
    }
}
```

### ４、ギフトUIView作成
![スクリーンショット 2019-12-22 0.50.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/1e89aa19-63c8-2b75-3c74-a87f8fe2288d.png)
![スクリーンショット 2019-12-22 1.28.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/9d7ca2a2-d75a-97d5-f10c-442bdeee6ff7.png)

```GiftView.swift
import SwiftUI

struct GiftView: View {
    var body: some View {
        ZStack{
            //重ねるギフトの絵作成
            Image("gift")
           .position(x: 130, y: 440)
            Image("gift1")
           .position(x: 150, y: 450)
            Image("gift2")
           .position(x: 220, y: 450)
        }
    }
}

struct GiftView_Previews: PreviewProvider {
    static var previews: some View {
        GiftView()
    }
}
```

### ５、文字UIView作成
![スクリーンショット 2019-12-22 0.50.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/1e89aa19-63c8-2b75-3c74-a87f8fe2288d.png)
![スクリーンショット 2019-12-22 1.28.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/9d7ca2a2-d75a-97d5-f10c-442bdeee6ff7.png)

```TextView.swift
import SwiftUI

struct TextView: View {
    var body: some View {
        //文字作成
        Text("Merry Christmas")
            //フォント設定
            .font(.largeTitle)
            //フォント太さ設定
            .fontWeight(.bold)
            .padding()
            //文字の色
            .foregroundColor(Color.white)
            //枠の線
            .background(Color.red)
            //文字と距離設定
            .padding(10)
            //枠の線の太さと色設定
            .border(Color.gray, width: 5)
        
    }
}

struct TextView_Previews: PreviewProvider {
    static var previews: some View {
        TextView()
    }
}
```

### ６、SwiftUIのContentViewにまとめる
![スクリーンショット 2019-12-22 0.50.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/1e89aa19-63c8-2b75-3c74-a87f8fe2288d.png)
![スクリーンショット 2019-12-22 1.28.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/9d7ca2a2-d75a-97d5-f10c-442bdeee6ff7.png)

```Swift:ContrntView.swift
import UIKit
import SwiftUI
import SpriteKit
struct ContentView: View {
    //@Stateプロパティを使ってUIの状態自動に同期
    @State private var displayTree = false
    
    var body: some View {
        //Z軸にビューを並べるコンポーネント
        ZStack{
            //縦軸にビューを並べるコンポーネント
            VStack{
                if(displayTree) {
                    ZStack{
                        //クリスマスツリーとギフトviewを呼び出す
                        TreeView()
                        GiftView()
                    }
                }
                Button(action: {
                    //ON/OFFを制御するコンポーネント
                    self.displayTree.toggle()
                }, label: {
                       TextView()
                })
            }
            //雪のviewを呼び出す
            SnowBackgroundView()
            //雪のviewを半透明にする
            .opacity(0.5)
        }.background(SwiftUI.Color.black.edgesIgnoringSafeArea(.all))
        
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
        
    }
}
```
### Merry Christmas :santa:
![イメージ.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538468/a9e6b913-b86a-fc8f-2f59-54e613c7dc78.gif)

###ソースコード 
https://github.com/Ricky-yu/XmasTree/tree/master