#swiftui #sprite-kit
Вопрос:
В продолжающемся стремлении передать данные из сцены SpriteKit в представление SwiftUI я обнаружил следующую загадку (по крайней мере, для меня). Я надеюсь, что это решение может вывести нас из тупика. У меня есть представление содержимого, которое использует SpriteView() для размещения/отображения сцены SpriteKit под названием GameScene. У меня есть класс под названием Counter(), который относится к подклассу ObservableObject. (Обратите внимание на инструкцию печати в теле функции добавления(подсчета).)
import SwiftUI
class Counter: ObservableObject {
@Published var count : Int = 0
func add(count: Int) {
self.count = count
print("Add (count); new total: (self.count)")
}
}
В contentView, с целью тестирования и сравнения, я добавил кнопку, которая вызывает функцию добавления(подсчета) :
import SwiftUI
import SpriteKit
struct ContentView: View {
@ObservedObject var counter = Counter()
var scene: SKScene {
let scene = GameScene()
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)
} label: {
Text("Add to count")
}
Text("New count = (counter.count)")
}
}
}
Когда нажимается кнопка (в представлении содержимого), количество увеличивается и отображается немедленно, как и ожидалось.
В GameScene у меня есть практически тот же вызов функции добавления(подсчета), но он завершается неудачей (отказывается?) чтобы обновить представление содержимого.
class GameScene: SKScene {
var counter = Counter()
var count = 0
...
//a SpriteKitNode called "button" is created then added in didMove(toView)//
...
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
let location = touch.location(in: self)
if button.contains(location) {
counter.add(count: 1)
}
}
}
Инструкция print читается одинаково независимо от того, поступает ли вызов из GameScene или contentView. При первом нажатии любой из кнопок на нем появляется надпись:
Добавить 1; новое общее количество: 1
Добавить 1; новое общее количество: 2
Добавьте 1; новое общее число: 3 и так далее.
Другими словами, вплоть до вызова функции, предназначенной для обновления опубликованного var, они, похоже, ведут себя одинаково. Но…
Тайна:
Почему вызов из contentView вызывает желаемое обновление, в то время как тот же вызов из GameScene этого не делает?
Я с нетерпением жду, когда с моих усталых глаз снимут чешую!
Ответ №1:
В вашем GameScene
случае вы создаете совершенно новый экземпляр Counter
, когда объявляете свойство:
var counter = Counter()
Вместо этого вы должны передавать экземпляр Counter
owned by ContentView
to GameScene
, чтобы они мутировали один и тот же объект.
Вы могли бы создать инициализатор GameScene
, чтобы использовать a Counter
в качестве параметра, или вы могли бы сделать что-то вроде этого:
//in GameScene:
var counter : Counter?
//in GameScene when the button is pressed:
counter?.add(count: 1)
//in ContentView:
let scene = GameScene()
scene.counter = counter
Комментарии:
1. Я последовал предложению @jnpdx, которое также требовало изменить вызов в GameScene на счетчик?.добавить(количество: 1), и теперь это работает. Я подозревал, что проблема была в воссоздании экземпляра, и попытался использовать счетчик var: Счетчик? Но мне не хватало смены сцены в contentView. Большая благодарность за то, что нашли время помочь!