15

我没有在 Sprite Kit 中找到任何对阴影或字体轮廓的支持。对于投影,我猜我可以创建第二个 SKLabelNode 并将其偏移到另一个后面。

有什么方法可以利用 SKEffectNode 作为轮廓或阴影?可能使 SKLabelNode 成为 SKEffectNode 的子节点?

更新 :

我能够使用第一个后​​面的第二个 SKLabelNode 获得一个不错的阴影,即黑色和偏移。仍然对其他潜在选择感兴趣,但这似乎运作良好。

4

10 回答 10

18

这很可能是您正在做的事情,但它有效且简单。

- (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;
}

也会尝试制作轮廓...但我觉得它会更棘手...必须有一种使用位图字体的方法.. ??? bm字形...

于 2013-10-07T05:40:01.503 回答
7

由于 iOS 11 SKLabelNode 有attributedText属性。您需要指定strokeColorstrokeWidth并且不要忘记fontforegroundColor

于 2017-12-07T14:01:19.553 回答
4

通过不仅使用此处描述的“2 SKLabelNode”投影技术,还通过添加另外三个“投影”,我已经能够获得一些可以接受的“轮廓”。

换句话说,一旦你有了底部的阴影,再添加三个。一个向顶部偏移,一个向右偏移,一个向左偏移——所以我在下面有四个“阴影”,主标签在顶部,总共五个 SKLabelNodes 只是为了创建这个轮廓效果。

在我的应用程序中,我必须为这个文本设置动画,所以我更进一步,从这五个标签创建了一个位图纹理,并从这个纹理创建了一个 SKSpriteNode,这让我可以删除五个原始标签节点,并制作动画位图版本。

还可能值得注意的是,通过从标签节点创建纹理会导致纹理模糊,我通过在创建纹理之前将标签节点的大小加倍来解决此问题,然后将生成的纹理大小减小50% .

我附上一张图片来向您展示结果。这可能不是最优雅的方法,但它似乎适用于我的特定情况。希望这可以帮助!

在此处输入图像描述

于 2015-09-30T06:00:38.950 回答
3

除了 Kelin 的出色之处,这里是它的Swift 4代码:

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:要同时获得描边填充,需要对 应用负值.strokeWidth表示描边朝外。的正值.strokeWidth将向内发送笔画并导致您的填充颜色 ( .foregroundColor) 消失!

于 2018-06-14T08:20:10.677 回答
2

我建议MKOutlinedLabelNode

例子:

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

在此处输入图像描述

您还可以查看ASAttributedLabelNode

于 2016-09-03T18:41:11.890 回答
1

这对我有用:

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

这是我与 ASAttributedLabelNode 一起使用的代码(其中一些是特定于我的,例如字体名称/大小/填充颜色/轮廓颜色,但当然只使用您自己的):

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
}

连同以下内容一起使用此功能:

    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)
于 2015-07-06T21:01:02.757 回答
0

关于大纲:

简短的回答:你已经完成了你的工作。
长答案:您确实为您完成了工作。

我们一直在一个项目上这样做,基本的方法是创建一个 UILabel 并将其渲染为进入精灵的纹理。
要将轮廓放到 UILabel 上,您可以使用: 如何让 UILabel 显示轮廓文本? 并将其渲染为 UIImage(您可以使用 [SKTexture textureWithImage:img] 制作纹理),使用此: 如何从 UILabel 创建图像? 这带来了一大堆问题,其中主要是缓慢、贪婪的渲染,这在很大程度上是通过尽可能将静态文本预渲染到文件来解决的。

由于字体往往需要精度,我认为您无法使用效果节点来实现这一点。回想起来,在走这条路之前,我会三思而后行。

于 2013-10-06T18:08:55.593 回答
0

我创建了一个继承自 SKSpriteNode 的类,它根据传递给构造函数的参数创建必要的 SKLabelNode 和 4 个阴影标签。

更改任何公共属性时都需要调用 update() 方法。(BorderSize 超过 6-7 看起来很有趣。)

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) )
        }
    }
}

最近的代码可以在https://gist.github.com/detaybey/214b23731a3b4d0344ce58643795f4b7找到

于 2016-11-11T14:18:50.613 回答
0

Erica Sadun 曾经根据SKEffectNode 这里创建了一个阴影

我最近不得不创建她的 Swift4 版本ShadowLabelNodehttps ://gist.github.com/Bersaelor/d6ea241278665173485e8aabafbe9047

于 2018-08-16T11:23:26.320 回答
0

使用面向对象!我已经将它实现为一个新组件,它是 SKNode 的后代,它包含两个 SKLabelNode,一个用于文本本身,另一个用于其阴影:

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")
    }
}

像这样实例化并添加到父节点(另一个节点或场景):

   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)

一篇大纲?好吧,没有什么能阻止您嵌套另一个 SKLabelNode 来建立轮廓。(可以计算它比标签略大。)请注意,添加子标签的顺序是相关的。

此代码已经过测试,并且正在我当前正在构建的 Apple TV 应用程序中积极使用。亲切的问候,特德。

于 2016-08-19T22:55:45.150 回答