By definition something that is immutable can't change, so in order to update an immutable game object a new object that contains the updates must be created.
type Player(score, x, y) =
member this.addScore(amount) =
Player(score + amount, x, y)
member this.addX(amount) =
Player(score, x + amount, y)
member this.addY(amount) =
Player(score, x, y + amount)
let first = Player(0, 0, 0)
let firstMoved = first.addX(2)
Passing every variable to the constructor can get unwieldy and slow. To avoid this organize data into different classes. This will allow for the reuse of smaller objects to create bigger ones. Since these objects are immutable, they will always contain the same data and can be reused freely without worry.
type Stats(score, lives) =
member this.addPoints(points) =
Stats(score + points, lives)
type Location(x, y) =
member this.move(x2, y2) =
Location(x + x2, y + y2)
type Player(stats : Stats, location : Location) =
member this.addScore(amount) =
Player(stats.addPoints(amount), location)
member this.addX(amount) =
Player(stats, location.move(amount, 0))
let first = Player(Stats(0, 1), Location(0, 0))
let firstMoved = first.addX(2)
F# also supports mutable data. You can write your original class like this.
type Player() =
inherit GameObject()
let mutable score = 0
let mutable x = 0
let mutable y = 0
member this.addScore(amount) =
score <- score + amount
member this.addX(amount) =
x <- x + amount
member this.addY(amount) =
y <- y + amount