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

后端 未结 10 1800
不思量自难忘°
不思量自难忘° 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:38

    Since iOS 11 SKLabelNode has attributedText property. You need to specify strokeColor, strokeWidth and don't forget font and foregroundColor.

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

    This worked for me:

    http://battleofbrothers.com/sirryan/outline-text-in-spritekit

    Here's the code I used in conjunction with ASAttributedLabelNode (some of it's specific to me like the font name/size/fillcolor/outlinecolor but of course just use your own):

    func outlinedCenteredString(string : String, size: CGFloat) -> NSAttributedString
    {
        var myMutableString : NSMutableAttributedString
        var font =  UIFont(name: "Super Mario 256", size: size)!
        var alignment : CTTextAlignment = CTTextAlignment.TextAlignmentCenter
        let alignmentSetting = [CTParagraphStyleSetting(spec: .Alignment, valueSize: Int(sizeofValue(alignment)), value: &alignment)]
        var paragraphRef = CTParagraphStyleCreate(alignmentSetting, 1)
    
        let textFontAttributes = [
            NSFontAttributeName : font,
            // Note: SKColor.whiteColor().CGColor breaks this
            NSForegroundColorAttributeName: UIColor.yellowColor(),
            NSStrokeColorAttributeName: UIColor.blackColor(),
            // Note: Use negative value here if you want foreground color to show
            NSStrokeWidthAttributeName:-3
            //,NSParagraphStyleAttributeName: paragraphRef
        ]
    
        myMutableString = NSMutableAttributedString(string: string, attributes: textFontAttributes as [NSObject : AnyObject])
    
        let para = NSMutableParagraphStyle()
        para.headIndent = 00
        para.firstLineHeadIndent = 00
        para.tailIndent = 0
        para.lineBreakMode = .ByWordWrapping
        para.alignment = .Center
        para.paragraphSpacing = 0
        myMutableString.addAttribute(
            NSParagraphStyleAttributeName,
            value:para, range:NSMakeRange(0,1))
        return myMutableString
    }
    

    along with the following to use this function:

        let hintSize = CGFloat(80.0)
        let hintLabel = ASAttributedLabelNode(size:CGSizeMake(playableRect.size.width*0.9, hintSize))
    
        hintLabel.attributedString = outlinedCenteredString("Touch the Rope to Release the Wood", size: hintSize)
    
        hintLabel.position =
            CGPointMake(
                size.width/2.0,
                ((size.height - playableRect.size.height)/2.0) + hintSize/2.0
        )
    
        hintLabel.zPosition = kHintZPosition
        addChild(hintLabel)
    
    0 讨论(0)
  • 2020-12-14 11:38

    Further to Kelin's excellent point, here is the Swift 4 code for it:

    var label: SKLabelNode!
    let attStr: NSMutableAttributedString = NSMutableAttributedString(string: "MyDefaultText")
    let myFont: UIFont = UIFont(name: "FontName", size: 7)!
    
    attStr.mutableString.setString("MyText")
    attStr.addAttribute(.font, value: myFont, range: NSMakeRange(0, attStr.length))
    attStr.addAttribute(.foregroundColor, value: UIColor.white, range: NSMakeRange(0, attStr.length))
    attStr.addAttribute(.strokeColor, value: UIColor.red, range: NSMakeRange(0, attStr.length))
    attStr.addAttribute(.strokeWidth, value: -3.0, range: NSMakeRange(0, attStr.length))
    
    label.attributedText = attStr
    

    PS: To get the stroke and the fill at the same time, you need to apply a negative value to the .strokeWidth which means the stroke heads outwards. A positive value for the .strokeWidth will send the stroke inwards and cause your fill colour (.foregroundColor) to disappear!

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

    This is most likely what you are doing, but it works and is simple.

    - (SKLabelNode *) makeDropShadowString:(NSString *) myString
    {
        int offSetX = 3;
        int offSetY = 3;
    
        SKLabelNode *completedString = [SKLabelNode labelNodeWithFontNamed:@"Arial"];
        completedString.fontSize = 30.0f;
        completedString.fontColor = [SKColor yellowColor];
        completedString.text = myString;
    
    
        SKLabelNode *dropShadow = [SKLabelNode labelNodeWithFontNamed:@"Arial"];
        dropShadow.fontSize = 30.0f;
        dropShadow.fontColor = [SKColor blackColor];
        dropShadow.text = myString;
        dropShadow.zPosition = completedString.zPosition - 1;
        dropShadow.position = CGPointMake(dropShadow.position.x - offSetX, dropShadow.position.y - offSetY);
    
        [completedString addChild:dropShadow];
    
        return completedString;
    }
    

    Will try and make outline one as well... but I have a feeling it'll be more tricky... there must be a way to use bitmap fonts .. ??? bmGlyph ...

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

    Use OOP! I've implemented this as a new component, a descendant of SKNode, which contains two SKLabelNodes, one for text itself and another for its shadow:

    final class TgSKLabelWithShadow: SKNode
    {
        private var lblText: SKLabelNode!
        private var lblShadow: SKLabelNode!
    
        var text: String?
            {     get { return lblText.text }
            set { lblText.text   = newValue
                  lblShadow.text = newValue   } }
    
        var fontColor: UIColor?
            { get { return lblText.fontColor     }
              set { lblText.fontColor = newValue } }
        // define additional getters/setters, if necessary.
    
    
        init(     position: CGPoint,
                  alignment: SKLabelHorizontalAlignmentMode,
                  text: String,
                  fontName: String,
                  fontSize: CGFloat,
                  fontColor: UIColor,
                  shadowColor: UIColor,
                  shadowOffSet: CGPoint)
        {
            super.init()
            self.position = position
    
            lblShadow = SKLabelNode(text: text)
            lblShadow.fontName  = fontName
            lblShadow.fontColor = shadowColor
            lblShadow.fontSize  = fontSize
            lblShadow.horizontalAlignmentMode = alignment
            lblShadow.position = shadowOffSet
            self.addChild(lblShadow)  // add shadow first
    
            lblText = SKLabelNode(text: text)
            lblText.fontName  = fontName
            lblText.fontColor = fontColor
            lblText.fontSize  = fontSize
            lblText.horizontalAlignmentMode = alignment
            self.addChild(lblText)  // on top of shadow
        }
    
        required init?(coder aDecoder: NSCoder)
        {
            fatalError("TgSKLabelWithShadow - init(coder:) has not been implemented")
        }
    }
    

    Instantiate and add to parent (another node or the scene) like so:

       ndInfo2 = TgSKLabelWithShadow(
            position: CGPoint(x: size.width/2, y:   size.height - 170),
            alignment : .Center,
            text: "ndInfo2: ???",
            fontName: "Avenir",
            fontSize: 40,
            fontColor: colorText,
            shadowColor: UIColor.blueColor(),
            shadowOffSet: CGPoint(x:1, y:-1))
        addChild(ndInfo2)
    

    An outline? Well, nothing prevents you to nest yet another SKLabelNode to establish an outline. (one could calculate it to be slightly bigger than the label.) Note that the order of adding child labels is relevant.

    This code has been tested and is in active use in an Apple TV app that I am currently building. Kind Regards, Ted.

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

    Erica Sadun once created a drop shadow based on SKEffectNode here

    I recently had to create a Swift4 version of her ShadowLabelNode: https://gist.github.com/Bersaelor/d6ea241278665173485e8aabafbe9047

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