LoginSignup
1
2

SpriteKitのテンプレート for SwitfUI

Posted at

はじめに

約4年前に書いた「【備忘録】SpriteKitのテンプレート」は、Storyboardを使っていましたが、最近はSwiftUIを使う機会が増えたので、今回は、SwiftUI向けの「SpriteKitのテンプレート」をまとめておきます。

この記事を執筆したときの環境は以下の通り

  • macOS : 13.4.1 (Ventura)
  • Xcode : 14.3.1
  • Swift : 5.8.1
  • SwiftUI : 4.0 (for iOS16)

Xcode新規プロジェクトの作成

Xcodeのメニューから「File」→「New」→「Project」の
「Game」テンプレートを選択してプロジェクトを作成すると、従来のStoryboardを使った(SwiftUIでは無い)プロジェクトになってしまうため、通常の「App」テンプレートを選択する。
続く「Choose options for your new project:」ダイアログにて以下を指定する。

  • Interface : SwifuUI
  • Language : Swift
  • 他 : 任意

ContentView.swiftの内容を書き換える

「ContentView.swift」を以下の内容に書き換える。
SpriteView(従来のSKView)のOptionDebugOptionsは、必要により指定する。

ContentView.swift
import SwiftUI
import SpriteKit

struct ContentView: View {
    var body: some View {
        let spriteViewOptions: SpriteView.Options = [
            //.allowsTransparency,
            //.ignoresSiblingOrder,
            //.shouldCullNonVisibleNodes,
        ]
        let spriteViewDebugOptions: SpriteView.DebugOptions = [
            .showsDrawCount,
            .showsFPS,
            //.showsFields,
            .showsNodeCount,
            //.showsPhysics,
            //.showsQuadCount,
        ]
        GeometryReader {
            SpriteView(scene: GameScene(size: $0.size),
                       options: spriteViewOptions,
                       debugOptions: spriteViewDebugOptions)
            .scaledToFill()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

GameScene.swiftを新規ファイルで作成する

「New File...」→「Swift File」からGameScene.swiftを新規作成する。

「GameScene.swift」を以下の内容に書き換える。

実は、GameScene.swiftは従来のまま。もし、Storyboardで開発した旧プロジェクトがあるなら、そこからGameScene.swiftをコピーして使用できるはず。

GameScene.swift
import SpriteKit

class GameScene: SKScene {

    enum ColliderType {
        static let xxx1: UInt32   = 1 << 0
        static let xxx2: UInt32   = 1 << 1
        static let xxx3: UInt32   = 1 << 2
        static let xxx4: UInt32   = 1 << 3
        static let xxx5: UInt32   = 1 << 4
    }

    override func didMove(to view: SKView) {
        self.physicsWorld.gravity = CGVector(dx: 0.0, dy: -2.0)
        self.physicsWorld.contactDelegate = self
        //TODO

    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches {
            let location = touch.location(in: self)
            let touchedNode = atPoint(location)
            switch touchedNode.name {
            case "xxx":
                //TODO
                break
            default:
                break
            }

        }
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        //TODO

    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        //TODO

    }

    override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
        //TODO

    }


    override func update(_ currentTime: TimeInterval) {
        //TODO

    }
}

extension GameScene: SKPhysicsContactDelegate {
    func didBegin(_ contact: SKPhysicsContact) {
        //TODO

    }
}

SpriteKitテンプレートとしては、以上でおわり。

おまけ

以前の記事で紹介した内容より、もっといい感じで書く方法があったので、紹介します。

SpriteKitでノードを構築していく場合に、インスタンス生成後に各プロパティを設定するコードがだらだら続くが、これをいい感じに書く方法を見つけたので、追記しておく。

普通の書き方
let label = SKLabelNode(fontNamed: "HelveticaNeue")
label.horizontalAlignmentMode = .center
label.verticalAlignmentMode = .center
label.text = "LABEL"
label.fontSize = 32
label.fontColor = .white
label.position = CGPoint(x: view.frame.midX, y: view.frame.midY)
addChild(label)
前回紹介した書き方
let label: SKLabelNode = {
    $0.horizontalAlignmentMode = .center
    $0.verticalAlignmentMode = .center
    $0.text = "LABEL"
    $0.fontSize = 32
    $0.fontColor = .white
    $0.position = CGPoint(x: view.frame.midX, y: view.frame.midY)
    return $0
} (SKLabelNode(fontNamed: "HelveticaNeue"))
addChild(label)
今回紹介する書き方
let label = SKLabelNode(fontNamed: "HelveticaNeue").apply {
    $0.horizontalAlignmentMode = .center
    $0.verticalAlignmentMode = .center
    $0.text = "LABEL"
    $0.fontSize = 32
    $0.fontColor = .white
    $0.position = CGPoint(x: view.frame.midX, y: view.frame.midY)
}
addChild(label)

applyメソッドは、次のように定義する。

public protocol Applicable { }
public extension Applicable {
    @discardableResult
    func apply(block: (Self) -> Void) -> Self {
        block(self)
        return self
    }
}

extension NSObject: Applicable { }

NSObjectextensionとして定義するため、ほとんどのオブジェクトで使うことができる。これは便利。(周知の内容かと思いますが・・・)

以上

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2