I'm trying to display a right-aligned timecode in my game. I had expected that digits would all have the same width, but this doesn't seem to be the case in SpriteKit, even though it seems to be the case in AppKit.
In SpriteKit, with the default font there is a noticeable difference in width between the digit 1 and the rest (1 is thinner), so whenever displaying a number with the least significant digit 1 all preceding digits shift slightly to the right. This happens even when setting a NSAttributedString with a font that has a fixedAdvance attribute.
class GameScene: SKScene {
override func didMove(to view: SKView) {
let label = SKLabelNode(text: "")
view.scene!.addChild(label)
// label.horizontalAlignmentMode = .left
label.horizontalAlignmentMode = .right
var i = 11
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { _ in
label.text = "\(i)"
// let font = NSFont(descriptor: NSFontDescriptor(fontAttributes: [.name: "HelveticaNeue-UltraLight", .fixedAdvance: 20]), size: 30)!
// let paragraphStyle = NSMutableParagraphStyle()
// paragraphStyle.alignment = .right
// label.attributedText = NSAttributedString(string: "\(i)", attributes: [.font: font, .foregroundColor: SKColor.labelColor, .paragraphStyle: paragraphStyle])
i += 5
}
}
}
With AppKit, when using SpriteKit's default font HelveticaNeue-UltraLight, this issue doesn't exist, regardless whether I set the fixedAdvance font attribute.
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
let font = NSFont(descriptor: NSFontDescriptor(fontAttributes: [.name: "HelveticaNeue-UltraLight"]), size: 30)!
// let font = NSFont(descriptor: NSFontDescriptor(fontAttributes: [.name: "HelveticaNeue-Light", .fixedAdvance: 20]), size: 30)!
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .right
let textField = NSTextField(labelWithString: "")
textField.font = font
textField.alignment = .right
// textField.alignment = .left
textField.frame = CGRect(x: 100, y: 100, width: 100, height: 100)
view.addSubview(textField)
var i = 11
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { _ in
textField.stringValue = "\(i)"
// textField.attributedStringValue = NSAttributedString(string: "\(i)", attributes: [.font: font, .paragraphStyle: paragraphStyle])
i += 5
}
}
}
Is there a solution to this problem?
label.calculateAccumulatedFrame().width:for the first 30 integers and single digits don't even have consistent widths. it appears to be highly contextual -- even for supposedly fixed-width fonts like Menlo or Courier. ex: you'd expect the width delta from 0 to 1 to be the same as the delta from 10 to 11; but no joy. one solution: you could roll your own font using textures for the integers 0-9. that way you have full control over width. i've done that before for fonts that require pixel perfect accuracy