This was a series of tweets.
https://twitter.com/mevdev/status/1318779823951507456
Game Data Design is something I learned best by doing. I’ve released 4 games on the app store (only one is still available). I’ve gotten to a playable game with 4 others. I am by no means an expert but I feel like I’ve learned a lot and now know how it works best for me.
Have a model that holds your data and state. Make it separated from your UI so it changes its own state. Build for serialization (save/open). Write and rewrite in an evolutionary manner. Make the UI an engine that reacts to and drives your model’s data and state.
A good model will ease all scenarios making bugs easier to fix but also the ability to save/resume a game in any state. Practice good naming. Make variable names verbose if that describes them well. Do not reuse terms for unrelated items. Be a bit silly at times.
I start by roughing out a model and to understand state. Understanding data transformations and calculations will suss out player objects vs the model. What holds what, which direction should communication flow. How is a turn kept track of.
This is my current game’s state enumeration:
enum State { case startingGame, rolling, rolledAwaitingSelection, selectedRoll, awaitingStopOrContinue, awaitingLocalPlayerRoll, busted, win, // network game only waitingOnNetworkPlayers }
// My main model variables:
struct GameModel { var players: [Player] var state: State //MARK: Potential and Selection Calculated vars var currentSelections: [DiePairing] var gameBoardPotentialKeys: [Int] var availableNumbers: [Int]
Model manipulation and UI interaction
func isAvailableNumber(_ num: Int) -> Bool // MARK: - Mutation for States mutating func rolling() mutating func selectedRoll(_ pairing: [Int]) mutating func stopSelected() mutating func currentPlayerRoll()
// Player turn management
// MARK: Turn Management
func nextPlayerIndex() -> Int func nextPlayer() -> Player mutating func continueToNextPlayer() mutating func continueSelected() -> Bool mutating func didSomeoneJustWin() -> Player?
// MARK: State Observation
func isWinningState() -> Bool func isBusted() -> Bool }
I know when the model is changed & how it changes state. It holds an array of Players which encapsulate their own data (If I were on a team more would be private).
// The Player manages its board, potential board & win state. I allow the UI to introspect in to draw.
struct Player { var gameBoard: [Int: Int] var gameBoardPotential: [Int: Int] var hasWon: Bool func winningRowsCount() -> Int func winningRows() -> [Int]
// Then this last bit changes the state of Player
mutating func addPotentialDie(_ die: Die) { mutating func convertPotential() mutating func convertPotentialToGameBoard() }
Maybe this isn’t the best way but it currently works for me.
Thanks for playing!
I realized after writing that ‘func convertPotential()’ was an exact duplicate and not called. It was more elegant though so I tested it then used that. I should be making a TestFlight build next week for testing. Also all of my structs and enums conform to Codable btw.