What would be the best approach for outlining or dropshadowing a font?

后端 未结 10 1801
不思量自难忘°
不思量自难忘° 2020-12-14 11:00

I\'m not finding any support for dropshadow or outline of a font in Sprite Kit. For the dropshadow, I\'m guessing I could create a second SKLabelNode and offset it behind t

相关标签:
10条回答
  • 2020-12-14 11:46

    I've been able to achieve a somewhat acceptable "outline" by not only using the "2 SKLabelNode" dropshadow techniques described here, but also by adding three more "drop shadows".

    In other words, once you have the bottom dropshadow in place, add three more. One offset toward the top, one offset toward the right, and one offset toward the left — so I have four "drop shadows" underneath, with the main label on top for a total of five SKLabelNodes just to create this outline effect.

    In my app, I have to animate this text, so I took it one step further and created a bitmap texture from these five labels and created a single SKSpriteNode from this texture, which allowed me to then delete the five original label nodes, and animate the bitmap version.

    It might also be worth noting that by creating a texture from the label nodes, it resulted in a blurry texture, which I fixed by doubling the size of the label nodes before creating the texture, then reducing the size of the generated texture by 50%.

    I am attaching an image to show you the result. It may not be the most elegant approach, but it seems to work for my particular situation. Hope this helps!

    0 讨论(0)
  • 2020-12-14 11:53

    With respect to outlining :

    Short answer: You've got your work cut out for you.
    Long answer: You've really got your work cut out for you.

    We have been doing this on a project and the basic approach has been to create a UILabel and render it to a texture that goes into a sprite.
    To get the outline onto the UILabel, you can use this: How do I make UILabel display outlined text? and to render that into a UIImage (that you can make a texture with [SKTexture textureWithImage:img]), use this : How to create an image from UILabel? This comes with a fist-full of problems, chief among them being slow, greedy rendering which was largely solved by pre-rendering to file whenever possible for static text.

    I don't think you'll be able to pull this off with an effect node because of the precision that fonts tend to require. In retrospect, I would think twice before going down this road.

    0 讨论(0)
  • 2020-12-14 11:57

    I created a class inheriting from SKSpriteNode where it creates necessary SKLabelNode and 4 shadow labels according to the parameters passed to constructor.

    You need to call the update() method when you changed any public property. (BorderSize more than 6-7 looks funny.)

    import Foundation
    import SpriteKit
    
    class LFOutlinedLabel : SKSpriteNode {
    
        private let skewX : [CGFloat] = [-1, 1, 1,-1]
        private let skewY : [CGFloat] = [-1,-1, 1, 1]
    
        private var label : SKLabelNode = SKLabelNode()
        private var shadows : [SKLabelNode] = []
    
        public var borderOpacity : CGFloat = 1
        public var borderSize: CGFloat = 1
        public var borderColor: UIColor = UIColor.black
        public var text : String = "?"
        public var fontName : String = Fonts.OptimaExtraBlack.rawValue
        public var fontColor: UIColor = UIColor.white
        public var fontSize : CGFloat = 40
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            //self.setup()
        }
    
        override init(texture: SKTexture!, color: UIColor, size: CGSize) {
            super.init(texture: texture, color: color, size: size)
            //self.setup()
        }
    
        convenience init(size: CGSize, font: String, fSize: CGFloat, fColor: UIColor, bSize: CGFloat, bColor: UIColor, bOpacity: CGFloat)
        {
            self.init(texture: nil, color: UIColor.clear, size: size)
            self.fontName = font
            self.fontSize = fSize
            self.fontColor = fColor
            self.borderSize = bSize
            self.borderColor = bColor
            self.borderOpacity = bOpacity
            self.setup()
        }
    
        // create shadow labels
        private func setup() {
            if shadows.count == 0 {
                let width = self.size.width / 2
                let height = self.size.height / 2
                for j in 0...3 {
                    let shadow = SKLabelNode(text: self.text)
                    addChild(shadow)
                    shadow.verticalAlignmentMode = .center
                    shadow.horizontalAlignmentMode = .center
                    shadow.zPosition = 999
                    shadow.position = CGPoint(x: width + (skewX[j] * borderSize) , y: height + (skewY[j] * borderSize))
                    shadow.text = self.text
                    shadow.fontSize = self.fontSize
                    shadow.fontName = self.fontName
                    shadow.fontColor = borderColor
                    shadows.append(shadow)
                }
                let label = SKLabelNode(text: self.text)
                addChild(label)
                label.verticalAlignmentMode = .center
                label.horizontalAlignmentMode = .center
                label.zPosition = 1000
                label.position = CGPoint(x: width , y: height )
                label.text = self.text
                label.fontSize = self.fontSize
                label.fontName = self.fontName
                label.fontColor = fontColor
                self.label = label
            }
        }
    
        public func update(){
            let width = self.size.width / 2
            let height = self.size.height / 2
    
            self.label.fontSize = fontSize
            self.label.fontName = fontName
            self.label.fontColor = fontColor
            self.label.verticalAlignmentMode = .center
            self.label.horizontalAlignmentMode = .center
            self.label.text = text
            self.label.position = CGPoint(x: width  , y: height )
    
            for i in 0...3 {
                shadows[i].verticalAlignmentMode = .center
                shadows[i].horizontalAlignmentMode = .center
                shadows[i].fontColor = borderColor
                shadows[i].fontSize = fontSize
                shadows[i].alpha = borderOpacity
                shadows[i].fontName = fontName
                shadows[i].text = text
                shadows[i].position = CGPoint(x: width + (skewX[i] * borderSize) , y: height + (skewY[i] * borderSize) )
            }
        }
    }
    

    the recent code can be found at https://gist.github.com/detaybey/214b23731a3b4d0344ce58643795f4b7

    0 讨论(0)
  • 2020-12-14 11:58

    I suggest MKOutlinedLabelNode.

    Example:

    let textNode = MKOutlinedLabelNode(fontNamed: "Helvetica", fontSize: 32)
    textNode.borderColor = UIColor.blackColor()
    textNode.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Center
    textNode.fontColor = UIColor.blueColor()
    textNode.outlinedText = "Test"
    

    You can also check out ASAttributedLabelNode.

    0 讨论(0)
提交回复
热议问题