GameScene
import SpriteKit
import GameplayKit
import SwiftUI
class GameScene: SKScene, SKPhysicsContactDelegate, ObservableObject {
@Published var gameScore = 0
override func didMove(to view: SKView) {
backgroundColor = .yellow
physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
ball()
// addScore()
}
func ball() {
let ball = SKShapeNode(circleOfRadius: 50)
ball.position = CGPoint(x: 100, y: 100)
ball.fillColor = .blue
self.addChild(ball)
}
let removeLabel = SKAction.sequence([SKAction.fadeIn(withDuration: 0.3),
SKAction.wait(forDuration: 0.8), SKAction.fadeOut(withDuration: 0.3)])
override func sceneDidLoad() {
super.sceneDidLoad()
}
func addScore(){
if gameScore < 10 {
gameScore += 2
} else {
gameScore += 4
}
}
}
/////////////
GameScene2
import SpriteKit
import GameplayKit
class GameScene2: SKScene {
override func didMove(to view: SKView) {
backgroundColor = .blue
physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
}
override func touchesBegan(_ touches: Set, with event: UIEvent?) {
guard let touch = touches.first else { return }
let location = touch.location(in: self)
let box = SKSpriteNode(color: SKColor.red, size: CGSize(width: 40, height: 40))
box.position = location
box.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 40, height: 40))
addChild(box)
}
}
/////////////////////
ContentView
import SwiftUI
import SpriteKit
struct ContentView: View {
@State var switcher = false
@StateObject var gameScene: GameScene = GameScene() // <<: Here 3
var scene: SKScene {
let scene = GameScene()
scene.size = CGSize(width: 216, height: 216)
scene.scaleMode = .fill
// scene.backgroundColor = .yellow
return scene
}
var scene2: SKScene {
let scene2 = GameScene2()
scene2.size = CGSize(width: 216, height: 216)
scene2.scaleMode = .fill
return scene2
}
var body: some View {
// Text("Score: \(gameScene.gameScore)") // <<: Here 4
// .onTapGesture {
// gameScene.addScore() // <<: Here 5
// }
Button(action: {
gameScene.addScore()
}, label: {
Text("Score: \(gameScene.gameScore)")
})
if switcher {
SpriteView(scene: scene)
.frame(width: 256, height: 256)
.ignoresSafeArea()
.background(Color.red)
.onAppear {
scene2.isPaused = true
}
.onDisappear {
scene2.isPaused = false
}
} else {
SpriteView(scene: scene2)
.frame(width: 256, height: 256)
.ignoresSafeArea()
.background(Color.blue)
.onAppear {
scene.isPaused = true
}
.onDisappear {
scene.isPaused = false
}
}
Button {
withAnimation(.easeInOut(duration: 1.0)) {
switcher.toggle()
}
} label: {
Text("SceneMove")
}
}
}
swiftui
Counter
import SwiftUI
import SpriteKit
struct ContentView: View {
@ObservedObject var counter = Counter()
var scene: SKScene {
let scene = GameScene()
scene.counter = counter
scene.size = CGSize(width: 300, height: 400)
scene.scaleMode = .fill
return scene
}
var body: some View {
VStack{
SpriteView(scene: scene)
.frame(width: 300, height: 400)
.ignoresSafeArea()
// Button{
// counter.add(count: 1)
// counter.reset()
// } label: {
// Text("reset to count")
// }
Text("New count = \(counter.count)")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
/////////////////////////////////
Counter.swift
import SwiftUI
class Counter: ObservableObject {
@Published var count : Int = 0
func add(count: Int) {
self.count += count
// print("Add \(count); new total: \(self.count)")
}
func reset() { count = 0 }
}
//////////////////////////
GameScene.swift
import SwiftUI
import SpriteKit
class GameScene: SKScene {
var counter : Counter?
var count = 0
override func didMove(to view: SKView) {
physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
}
override func touchesBegan(_ touches: Set, with event: UIEvent?) {
guard let touch = touches.first else { return }
let location = touch.location(in: self)
let box = SKSpriteNode(color: SKColor.red, size: CGSize(width: 50, height: 50))
box.position = location
box.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 50, height: 50))
self.addChild(box)
// score += 1
// counter.add(count: 1)
counter?.add(count: 1)
}
}
StateObject
@StateObjectと@ObservedObjectの違い
StateObjectCounterは親Viewのcounterが更新されても値を保持しているのに対し、
OvservedObjectCounterは親Viewの値更新に伴い値が初期化されている。
ライフサイクルが異なる。
@ObservedObjectは親Viewが再描画される度(= 親Viewのプロパティが更新される度)に更新され、保持するViewが再描画される。
counter (親View)
StateObjectCounter (子View)
OvservedObjectCounter (子View)
import SwiftUI
struct ContentView: View {
@State var counter = 0
var body: some View {
VStack(alignment: .leading, spacing: 30) {
HStack {
Text("counter: \(counter)")
Button("count up") {
counter += 1
}
}
StateObjectCounter()
ObservedObjectCounter()
}
}
}
final class Counter: ObservableObject {
@Published var number = 0
func increment() { number += 1 }
func reset() { number = 0 }
}
struct StateObjectCounter: View {
@StateObject private var counter = Counter()
var body: some View {
HStack {
Text("StateObject: \(counter.number)")
Button("count up") {
counter.number += 1
}
Button("Reset") {
self.counter.reset()
}
}
}
}
struct ObservedObjectCounter: View {
@ObservedObject private var counter = Counter()
var body: some View {
HStack {
Text("OvservedObject: \(counter.number)")
Button("count up") {
counter.number += 1
}
}
}
}
SwiftUI&SpriteKit
ContentView.swift
import SwiftUI
import SpriteKit
struct ContentView: View {
var scene: SKScene {
let scene = GameScene()
scene.size = CGSize(width: 300, height: 400)
scene.scaleMode = .fill
return scene
}
var body: some View {
SpriteView(scene: scene)
.frame(width: 300, height: 400)
.ignoresSafeArea()
}
}
/*
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
import GameplayKit
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) {
backgroundColor = .blue
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?) {
}
}
SpriteKitBase
ContentView.swift
import SwiftUI
import SpriteKit
struct ContentView: View {
let screenWidth = UIScreen.main.bounds.width
let screenHeight = UIScreen.main.bounds.height
var scene: SKScene {
let scene = GameScene()
scene.size = CGSize(width: screenWidth, height: screenHeight)
scene.scaleMode = .fill
return scene
}
var body: some View {
SpriteView(scene: scene)
.frame(width: screenWidth, height: screenHeight)
.ignoresSafeArea()
}
}
///////////////////////////
GameScene.swift
import SpriteKit
import GameplayKit
class GameScene: SKScene {
override func didMove(to view: SKView) {
backgroundColor = .yellow
physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
}
func touchDown(atPoint pos : CGPoint) {
}
func touchMoved(toPoint pos : CGPoint) {
}
func touchUp(atPoint pos : CGPoint) {
}
override func touchesBegan(_ touches: Set, with event: UIEvent?) {
guard let touch = touches.first else { return }
let location = touch.location(in: self)
let box = SKSpriteNode(color: SKColor.red, size: CGSize(width: 50, height: 50))
box.position = location
box.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 50, height: 50))
addChild(box)
}
override func touchesMoved(_ touches: Set, with event: UIEvent?) {
}
override func touchesEnded(_ touches: Set, with event: UIEvent?) {
}
override func touchesCancelled(_ touches: Set, with event: UIEvent?) {
}
override func update(_ currentTime: TimeInterval) {
}
}