最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

sprite kit - SKLabelNode keeps jumping back and forth when displaying different numbers with equal number of digits - Stack Over

programmeradmin0浏览0评论

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?

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?

Share Improve this question asked Nov 20, 2024 at 10:24 NickkkNickkk 2,6571 gold badge27 silver badges36 bronze badges 1
  • i agree this is strange behavior. i just looked at 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 – Fault Commented Nov 21, 2024 at 13:55
Add a comment  | 

1 Answer 1

Reset to default 0

I found a workaround that causes the width of the least significant digit to be equal as the others:

label.numberOfLines = 0

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论