13

With SKLabelNode, it would appear that when you break to more than one line,

the results is always

abcde
fg

rather than

abcde
 fg

Really it seems that SKLabelNode is just left-aligned, and that's it.

Is there a solution - how to make multiline SKLabelNode center-align?


Note - horizontalAlignmentMode is totally unrelated. it simply allows you to choose whether the anchor of the overall label area is on the left, right or center of the position.

Fattie
  • 27,874
  • 70
  • 431
  • 719
  • 1
    You might try this link for multiline label nodes. It gives you a couple of different solutions. https://xcodenoobies.blogspot.com/2014/12/multiline-sklabelnode-hell-yes-please-xd.html In the comments, someone also suggested a Swift solution. I have not tried the code, but at least it will give you some examples to try. – Voltan Apr 29 '18 at 03:33
  • hi @Voltan your suggestion is indeed the only way forward. I put in an example class to do it that way. It's a shame you deleted your answer which was a good one! Thanks again! – Fattie May 04 '18 at 10:50

3 Answers3

18

I solved this issue by setting attributedText to SKLabelNode. Seemed like the easiest way to do it, hope Apple fixes this issue soon.

Swift 4

let attrString = NSMutableAttributedString(string: yourString)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
let range = NSRange(location: 0, length: yourString.count)
attrString.addAttribute(NSAttributedStringKey.paragraphStyle, value: paragraphStyle, range: range)
attrString.addAttributes([NSAttributedStringKey.foregroundColor : UIColor.black, NSAttributedStringKey.font : UIFont.systemFont(ofSize: 30)], range: range)
yourLabelNode.attributedText = attrString
Martin Škorc
  • 206
  • 1
  • 3
3

It seems that Apple's SKLabel simply does not center multi-line text. (As of 2018.)

The behavior can only be described as broken - the second and latter lines just flush left no matter what setting.

One solution is to use a "second label", example below.

Later...

@MartinŠkorc seems to have discovered you can use AttributedString with SKLabels - so, great! Thanks Martin!

import SpriteKit

class StupidMultilineSKLabelNode: SKLabelNode {
    
    // Apple's SKLabel does not center multi-line text
    
    // this class works around the problem by making
    // a "sub" SKLabel for the second line
    
    // if the .text includes a newline, a line break,
    // this class will present it as a two-line SKLabel,
    // but properly centered (each line itself centered).
    // (this example allows just the one extra line)
    
    // please note,
    // this is not meant to be a generalized class;
    // rather it is meant to work quick in a specific case.
    // you can change it as needed
    
    // using a "second label" does seem to be the only solution
    // until Apple address the issue
    
    var stupidExtraLabel: SKLabelNode
    
    override init() {
        
        stupidExtraLabel = SKLabelNode()
        super.init()
        
        stupidExtraLabel.basicSettings()
        // the simplest approach: in "basicSettings" simply set
        // your point size, font, color, etc etc as you wish
        // just always use that call to set all labels in the project

        stupidExtraLabel.position = CGPoint(x: 0, y: -10)
        stupidExtraLabel.text = ""
        
        self.addChild(stupidExtraLabel)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override var alpha: CGFloat {
        
        didSet {
            
            super.alpha = alpha
            stupidExtraLabel.alpha = alpha
        }
    }
    
    override var fontColor: UIColor? {
        
        didSet {
            
            super.fontColor = fontColor
            stupidExtraLabel.fontColor = fontColor
        }
    }
    
    override var text: String? {
        
        didSet {
            
            let lines: [String] = text!.components(separatedBy: ["\n"])
            super.text = ""
            stupidExtraLabel.text = ""
            if lines.count > 0 { super.text = lines[0] }
            if lines.count > 1 { stupidExtraLabel.text = lines[1] }
            
            stupidExtraLabel.position = CGPoint(x: 0, y: -10)
        }
    }
}
Community
  • 1
  • 1
Fattie
  • 27,874
  • 70
  • 431
  • 719
3

Following up - I posted a link instead of code, which is kind of a no-no. I don't have a big rep (noob), so I also can't edit yet :)

I recently discovered that you can overlay UIKit on top of scenekit (probably Sprite Kit too). I've tried it and it works with no loss in FPS, so I'm removing all of my Spritekit overlays (menus/labels) and using the UIKit basics (UIButton, UILabel). If this is of interest, I can share some code. I'm still figuring things out, but far enough into it that I think it's going to work.

Voltan
  • 1,170
  • 1
  • 7
  • 16
  • Interested. Please share. – MACE Dec 05 '19 at 13:52
  • @MACE - set up a GameViewController, add a subview for the gameScene (SCNView). gameScene is just a subview so it's pretty much like any view controller. A quick test is to add something simple like a toolbar or label over the top of the SceneKit view. – Voltan Dec 07 '19 at 16:35
  • After spending a frustrating morning trying to build a sensible textbox overlay with shape and label nodes in SpriteKit, I can safely say - this is the way ‍♂️ – barrylachapelle Jul 26 '23 at 18:04