In my game, I want to show a replay of character movement after the level is completed. This is known as a Ghost.
I'd like to ask you to review the types I have set up for this. It should not blow up the stack or cause performamce degrading effects like memory fragmentation. The recording is constantly growing as you play, of course, meaning that more space in the seq is required and it might get re-allocated / copied if I'm doing things wrong. My grasp of Nim under the hood doesn't go that deep
type
Pose* = object
position*: Vect
angle*: Float
PlayerPose* = object
headPose*: Pose
frontWheelPose*: Pose
rearWheelPose*: Pose
Ghost* = ref object
poses*: seq[PlayerPose]
coinProgress*: float32
GameState* = ref object of RootObj
ghostRecording*: Ghost
## A ghost that is being recorded
ghostPlayback*: Ghost
## A ghost that represents the best time for the level
Usage:
proc pose(body: Body): Pose {.inline.} =
let position = body.position
result.position = body.position
result.angle = body.angle
proc newPlayerPose*(state: GameState): PlayerPose =
result.headPose = state.riderHead.pose
result.frontWheelPose = state.frontWheel.pose
result.rearWheelPose = state.rearWheel.pose
proc newGhost*(): Ghost =
Ghost(
poses: @[],
coinProgress: 0f,
)
proc addFrame*(ghost: var Ghost, state: GameState) {.inline.} =
print "poses len", ghost.poses.len # increasing by 1 every frame
ghost.poses.add(state.newPlayerPose)
## in game update loop:
state.ghostRecording.addFrame(state)
The code works, but my knowledge doesn't go deep enough to know whether the seq is copied for every frame, for example. Or that it might be better to use ref objects for all object types. Do you have any tips to improve on this code?
Where you used ref and where not seems ok as far as I can tell. However, usually you start with the non-ref version and then only if either performance is bad (copies) or else the logic requires shared mutable state to work properly things are changed to ref.
result.headPose = state.riderHead.pose is very bad code that will be flagged as wrong in upcoming versions, you really should use result = PlayerPose(headPose: ..., ...) instead.
I did have terrible performance issues related to the seq being copied when stored as a temp variable in a function scope. Thinking back on it, the problem there might have been that I used let while I should have used var.
I suspected as much with the direct result assignment. (hence the comment there). I'll change it.
Is there a preference between return PlayerPose() and result = PlayerPose()? AI seems to be exclusively suggesting the latter
Found a discussion on the return question here: https://forum.nim-lang.org/t/7130
Thanks for the help @Araq