I am trying to code the board game Splendor as a simple coding project in SwiftUI. I'm a bit of a hack so please point me in the right direction if I've got this all wrong. I'm also attempting to use the MVVM paradigm.
The game board has two stacks of tokens on it, one for unclaimed game tokens on and one for the tokens of the active player. There is a button on the board which allows the player to claim a single token at a time.
The tokens are drawn in a custom view - TokenView() - which draws a simple Circle() offset by a small amount to make a stack. The number of circles matches the number of tokens. Underneath each stack of tokens is a Text() which prints the number of tokens.
When the button is pressed, only the Text() updates correctly, the number of tokens drawn remains constant.
I know my problem something to do with the fact that I'm mixing an @ObservedObject and a static Int. I can't work out how to not use the Int, as TokenView doesn't know whether it's drawing the board's token collection or the active players token collection. How do I pass the count of tokens as an @ObservedObject? And why does Text() update correctly?
Model:
struct TheGame {
var tokenCollection: TokenCollection
var players: [Player]
init() {
self.tokenCollection = TokenCollection()
self.players = [Player()]
}
}
struct Player {
var tokenCollection: TokenCollection
init() {
self.tokenCollection = TokenCollection()
}
}
struct TokenCollection {
var count: Int
init() {
self.count = 5
}
}
ViewModel:
class MyGame: ObservableObject {
@Published private (set) var theGame = TheGame()
func collectToken() {
theGame.tokenCollection.count -= 1
theGame.players[0].tokenCollection.count += 1
}
}
GameBoardView:
struct GameBoardView: View {
@StateObject var myGame = MyGame()
var body: some View {
VStack{
TokenStackView(myGame: myGame, tokenCount: myGame.theGame.tokenCollection.count)
.frame(width: 100, height: 200, alignment: .center)
Button {
myGame.collectToken()
} label: {
Text ("Collect Token")
}
TokenStackView(myGame: myGame, tokenCount: myGame.theGame.players[0].tokenCollection.count) .frame(width: 100, height: 200, alignment: .center)
}
}
}
TokenStackView:
struct TokenStackView: View {
@ObservedObject var myGame: MyGame
var tokenCount: Int
var body: some View {
VStack {
ZStack {
ForEach (0..<tokenCount) { index in
Circle()
.stroke(lineWidth: 5)
.offset(x: CGFloat(index * 10), y: CGFloat(index * 10))
}
}
Spacer()
Text("\(tokenCount)")
}
}
}