SwiftUI + SpriteKit で重力シミュレーション

iOS

図のように白い球が自由落下して赤い球と衝突します。

SpriteKit の SKPhysicsBody を使うと物理シミュレーション環境を使用することができます。

画面をタップすると白い急がランダムな方向に加速するようになってるので、タップしまくるといろいろな動きを楽しむことができます。

今回、iOS 14 から追加された SpriteView を使用しています。 SwiftUI から直接 SpriteKit を読み込めるので超絶便利です。

SpriteView – A SwiftUI view that renders a SpriteKit scene.
<a href=”https://developer.apple.com/documentation/spritekit/spriteview” target=”_blank”>https://developer.apple.com/documentation/spritekit/spriteview</a>

ContentView.swift


import SwiftUI
import SpriteKit

struct ContentView: View {
    let width = UIScreen.main.bounds.size.width
    let height = UIScreen.main.bounds.size.height
    
    var body: some View {
        let scene = GameScene()
        scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
        scene.scaleMode = .resizeFill
        
        return SpriteView(scene: scene)
            .frame(width: width, height: height)
            .edgesIgnoringSafeArea(.all)
    }
}

GameScene.swift


import SpriteKit

class GameScene: SKScene {
    let width = UIScreen.main.bounds.size.width
    let height = UIScreen.main.bounds.size.height
    
    var shapeNode = SKShapeNode()
    
    override func didMove(to view: SKView) {
        let rect = CGRect(x: -1 * width / 2,
                          y: -1 * height / 2,
                          width: width,
                          height: height);
        self.physicsBody = SKPhysicsBody(edgeLoopFrom: rect)
 
        physicsWorld.gravity = CGVector(dx: 0.0,
                                        dy: -1.0)
        
        print("frame what?")
        print(frame)
        
        // 落下するボール
        shapeNode = SKShapeNode(circleOfRadius: 50)
        shapeNode.position = CGPoint(x: 0,
                                     y: 150)
        shapeNode.fillColor = .white
        shapeNode.strokeColor = .blue
        
        shapeNode.physicsBody = SKPhysicsBody(circleOfRadius: shapeNode.frame.width / 2)
        shapeNode.physicsBody?.isDynamic = true
        shapeNode.physicsBody?.linearDamping = 0.1
        shapeNode.physicsBody?.restitution = 0.8
        addChild(shapeNode)
        
        // 動かないボール
        let shapeNode3 = SKShapeNode(circleOfRadius: 50)
        shapeNode3.position = CGPoint(x: 40,
                                      y: -90)
        shapeNode3.fillColor = .red
        shapeNode3.strokeColor = .red
        
        shapeNode3.physicsBody = SKPhysicsBody(circleOfRadius: shapeNode.frame.width / 2)
        shapeNode3.physicsBody?.isDynamic = false
        shapeNode3.physicsBody?.affectedByGravity = false
        addChild(shapeNode3)
    }
    
    override func touchesBegan(_ touches: Set,
                               with event: UIEvent?) {
        shapeNode.physicsBody?.applyImpulse(CGVector(
                                                dx: Double(arc4random_uniform(200)) - 100.0,
                                                dy: Double(arc4random_uniform(200)) - 100.0))
    }
    
    override func touchesMoved(_ touches: Set,
                               with event: UIEvent?) {
    }
}

SwiftUIを学ぶのにおすすめの本

SwiftUI 徹底入門

SwiftUIではじめるiPhoneアプリプログラミング入門

iOS/macOS UIフレームワーク SwiftUIプログラミング

コメント

タイトルとURLをコピーしました