Confused
Confused

Reputation: 6278

SKLabel avoid, use TextKit instead then create SKTexture?

Staying in SpriteKit, is it possible to create more "artistic" text with the vastly greater control TextKit provides, and then (somehow) convert these strings to images so they can be used as SKSpriteNodes?

I ask because I'd like to do some more serious kerning stuff... much greater spacing, and a few other things that aren't possible with SKLabels, but are part of TextKit, but I'd like them to be bitmaps as soon as I'm done getting them to look the way I want.

But I can't find a way to turn A TextKit into an image.

Upvotes: 1

Views: 143

Answers (1)

bzz
bzz

Reputation: 5596

You can draw your text in a CGContext, then create a texture from it and assign that texture to a SKSpriteNode.

Here is an example from this GitHub project:

class ASAttributedLabelNode: SKSpriteNode {

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    init(size: CGSize) {
        super.init(texture: nil, color: UIColor.clear, size: size)
    }

    var attributedString: NSAttributedString! {
        didSet {
            draw()
        }
    }

    func draw() {
        guard let attrStr = attributedString else {
            texture = nil
            return
        }

        let scaleFactor = UIScreen.main.scale
        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue
        guard let context = CGContext(data: nil, width: Int(size.width * scaleFactor), height: Int(size.height * scaleFactor), bitsPerComponent: 8, bytesPerRow: Int(size.width * scaleFactor) * 4, space: colorSpace, bitmapInfo: bitmapInfo) else {
            return
        }

        context.scaleBy(x: scaleFactor, y: scaleFactor)
        context.concatenate(CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: size.height))
        UIGraphicsPushContext(context)

        let strHeight = attrStr.boundingRect(with: size, options: .usesLineFragmentOrigin, context: nil).height
        let yOffset = (size.height - strHeight) / 2.0
        attrStr.draw(with: CGRect(x: 0, y: yOffset, width: size.width, height: strHeight), options: .usesLineFragmentOrigin, context: nil)

        if let imageRef = context.makeImage() {
            texture = SKTexture(cgImage: imageRef)
        } else {
            texture = nil
        }

        UIGraphicsPopContext()
    }

}

Upvotes: 2

Related Questions