I'm moving my first steps into SpriteKt and found this apparently weird behaviour of the SkSpriteNode.position
property: it should be a CGPoint
, but when assigned and read back, it behaves differently of any other CGPoint.
In the code that follows I have tested some randomly chosen points. Some of them can be assigned to the SkSpriteNode.position
property and read back again and everything seems to work fine.
Some other, when assigned, are rounded to some other (close) value.
It could be a floating-point value representation round off issue, but than comes the super weird thing: the exact same CGPoint
, when assigned to another CGPoint
(not to the position
property, which, by the way, claims to be a CGPoint
) the round off doesn't appear š³
Does anybody knows what's going on?
check(position: CGPoint.zero)
check(position: CGPoint(x: 1, y: 1))
check(position: CGPoint(x: 100, y: 700))
check(position: CGPoint(x: -500, y: 200))
check(position: CGPoint(x: 0.5, y: 0.5))
check(position: CGPoint(x: 1.12, y: 1.14))
check(position: CGPoint(x: 1.12, y: 1.1415161718))
func check(position: CGPoint) {
let sprite = SKSpriteNode(color: .cyan, size: CGSize(width: 32, height: 32))
let point = position
sprite.position = position
print("position = \(position)")
print("point = \(point)")
print("sprite = \(sprite.position)")
if sprite.position == position {
print("ā
they match")
} else {
print("ā they don't match")
}
assert(position == point, "assign \(position) to point result in \(point)")
}
On my system (Xcode Version 12.5 (12E262)) output is:
position = (0.0, 0.0)
point = (0.0, 0.0)
sprite = (0.0, 0.0)
ā
they match
position = (1.0, 1.0)
point = (1.0, 1.0)
sprite = (1.0, 1.0)
ā
they match
position = (100.0, 700.0)
point = (100.0, 700.0)
sprite = (100.0, 700.0)
ā
they match
position = (-500.0, 200.0)
point = (-500.0, 200.0)
sprite = (-500.0, 200.0)
ā
they match
position = (0.5, 0.5)
point = (0.5, 0.5)
sprite = (0.5, 0.5)
ā
they match
position = (1.12, 1.14)
point = (1.12, 1.14)
sprite = (1.1200000047683716, 1.1399999856948853)
ā they don't match
position = (1.12, 1.1415161718)
point = (1.12, 1.1415161718)
sprite = (1.1200000047683716, 1.1415162086486816)
ā they don't match
Internally the sprite is using 32-bit single-precision floats. The normal CGPoint is 64-bit double-precision. Assigning sprite.position is rounding 64-bit to 32-bit, and then for the printing and comparison it's going back from 32-bit to 64-bit. Your initial examples all happen to be numbers that are exactly representable in both 32- and 64-bits, so no loss of precision is happening there.