I have a SwiftUI View holding a SpriteView. This SpriteView receives a Double value successful from a combine variable sitting in a conductor class:
var passThrough = PassthroughSubject<Double, Never>()
This is the SwiftUI View which receives the PassthroughSubject correct.
struct SpriteKitView: View {
@ObservedObject var sharedViewModel: SharedViewModel
var scene = GameScene()
init(sharedViewModel:SharedViewModel){
let width = UIScreen.main.bounds.width
let height = UIScreen.main.bounds.height
scene.size = CGSize(width: width, height: height)
scene.scaleMode = .fill
self.sharedViewModel = sharedViewModel
}
var body: some View {
SpriteView(scene: scene, options: [.allowsTransparency])
.onReceive(sharedViewModel.conductor.passThrough){ ( value ) in
print("Received Double: \(value)")
scene.scaleVar = CGFloat(value)
}
}
}
The GameScene is just a circle drawn as a SKShapeNode. Within the Update you can see the passThrough enter like so:
class GameScene: SKScene {
var scaleVar: Double = 0
var myObject: SKShapeNode!
override func didMove(to view: SKView) {
let node = SKShapeNode(circleOfRadius: 100)
node.position = CGPoint(x: size.width/2, y: size.height/2)
node.fillColor = SKColor.orange
myObject = node
addChild(myObject)
}
override func update(_ currentTime: TimeInterval) {
print("Update Double: \(scaleVar)")
myObject.setScale(CGFloat(scaleVar))
print("Update CGFloat: \(CGFloat(scaleVar))")
}
}
Going from SwiftUI to the SpriteKit the value gets converted to a random Number. See this console output of the prints within the code:
Received Double: 0.9631603454475357 <- correct value
Update Double: 0.03565312499999999 <- random static??
Update CGFloat: 0.03565312499999999 <- random static??
Update Double: 0.03565312499999999 <- random static??
Update CGFloat: 0.03565312499999999 <- random static??
Why is the update not receiving the send Double. The same thing happens when I translate to CGFloat before sending it.
I took your code and put it into a new iOS app project replacing the default "ContentView" with your SpriteKitView and and the following implementation of a SharedViewModel. I could not reproduce the results you report. The double value is published as expected in every case. Is there perhaps another explanation in your code?
import SwiftUI
import SpriteKit
import Combine
class SharedViewModel: NSObject, ObservableObject {
var passThrough = PassthroughSubject<Double, Never>()
override init() {
super.init()
self.sendDoubles()
}
private func sendDoubles() {
Task {
var angle = 0.0
while(true) {
guard !Task.isCancelled else { break }
angle = fmod(angle + 0.1, 2 * Double.pi)
passThrough.send(sin(angle))
try await Task.sleep(nanoseconds: UInt64(1.0e8))
}
}
}
}
class GameScene: SKScene {
var scaleVar: Double = 0
var myObject: SKShapeNode!
override func didMove(to view: SKView) {
let node = SKShapeNode(circleOfRadius: 100)
node.position = CGPoint(x: size.width/2, y: size.height/2)
node.fillColor = SKColor.orange
myObject = node
addChild(myObject)
}
override func update(_ currentTime: TimeInterval) {
print("Update Double: \(scaleVar)")
myObject.setScale(CGFloat(scaleVar))
print("Update CGFloat: \(CGFloat(scaleVar))")
}
}
struct ContentView: View {
@ObservedObject var sharedViewModel: SharedViewModel
var scene = GameScene()
init(sharedViewModel:SharedViewModel){
let width = UIScreen.main.bounds.width
let height = UIScreen.main.bounds.height
scene.size = CGSize(width: width, height: height)
scene.scaleMode = .fill
self.sharedViewModel = sharedViewModel
}
var body: some View {
SpriteView(scene: scene, options: [.allowsTransparency])
.onReceive(sharedViewModel.passThrough.receive(on: DispatchQueue.main)){ ( value ) in
print("Received Double: \(value)")
scene.scaleVar = CGFloat(value)
}
}
}