将数据从 SpriteKit 场景传回 SwiftUI

问题描述

我已经为此苦苦挣扎了一段时间。它让我彻夜难眠,让我害怕早上起床。 我有一个 SwiftUI ContentView,我从中调用一个名为 GameScene 的 SpriteKit 场景。 游戏结束后,我想用分数更新 ContentView。 事实证明,这比我想象的要困难得多。 我已经尝试过@EnvironmentObject、@Bindings、(等)UserDefaults、userData(在 SK 场景中)......将数据传递给 GameScene 很简单,但是如何让 ContentView 在得分时更新(重绘自身)变化? 我知道我们应该展示示例代码,但坦率地说,我已经尝试了很多次和很多方法,我不知道从哪里开始。如果有人可以向我保证这是可能的(首先)并且可能会指出我正确的方向,我将不胜感激! (并承诺在找到解决方案时分享我的解决方案。)谢谢! 这是我的 ObservableObject 类:

final class GameTracker: ObservableObject {
@Published var items: [CompletedChallenge] = []

var totalscore: Int {
    items.reduce(0) {$0 + $1.points}
}

func add(_ completedItem: CompletedChallenge) {
    items.append(completedItem)
   }
}
}

ContentView 是这样的:

struct ContentView: View {
@EnvironmentObject var game: GameTracker
var body: some View {
    
    vstack{
        NavigationView {
            List{
                ForEach(selectedChallenges) { challenge in
                    NavigationLink(
                        destination: DetailView(challenge: challenge)
                    ) {
                        HStack{
                            Image(systemName: game.items.contains { item in
                                item.challenge == challenge }
                                    ? "checkmark.circle.fill" : "arrowtriangle.right.circle")
                                .foregroundColor(.orange)
                            Text(challenge.name)
                            Spacer()
                        }
                        
                    }
                }
            }
            .navigationBarTitle(Text("Challenges"))
        }       
        Text("score: \(game.totalscore)")
    }
}
}

在此示例中,所选列表项导航到 DetailView,我可以在其中更新 ObservableObject:

@EnvironmentObject var game: GameTracker


 ...
        let newItem = CompletedChallenge(challenge: challenge,points: challenge.maxPoints)
        game.add(newItem)

当一切都在 SwiftUI 视图中时,这很有效。但是当我从 SpriteKit GameScene 调用 game.add(newItem) 时,我无法得到相同的结果。

解决方法

您的 totalScore 属性不是 @Published,因此 SwiftUI 视图不会在值更改时更新。

试试这个:

final class GameTracker: ObservableObject {
@Published var items: [CompletedChallenge] = []

@Published var totalScore: Int {   // <-- Here!
    items.reduce(0) {$0 + $1.points}
}

func add(_ completedItem: CompletedChallenge) {
    items.append(completedItem)
   }
}
}