我没有在 Sprite Kit 中找到任何对阴影或字体轮廓的支持。对于投影,我猜我可以创建第二个 SKLabelNode 并将其偏移到另一个后面。
有什么方法可以利用 SKEffectNode 作为轮廓或阴影?可能使 SKLabelNode 成为 SKEffectNode 的子节点?
更新 :
我能够使用第一个后面的第二个 SKLabelNode 获得一个不错的阴影,即黑色和偏移。仍然对其他潜在选择感兴趣,但这似乎运作良好。
我没有在 Sprite Kit 中找到任何对阴影或字体轮廓的支持。对于投影,我猜我可以创建第二个 SKLabelNode 并将其偏移到另一个后面。
有什么方法可以利用 SKEffectNode 作为轮廓或阴影?可能使 SKLabelNode 成为 SKEffectNode 的子节点?
更新 :
我能够使用第一个后面的第二个 SKLabelNode 获得一个不错的阴影,即黑色和偏移。仍然对其他潜在选择感兴趣,但这似乎运作良好。
这很可能是您正在做的事情,但它有效且简单。
- (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字形...
由于 iOS 11 SKLabelNode 有attributedText
属性。您需要指定strokeColor
,strokeWidth
并且不要忘记font
和foregroundColor
。
通过不仅使用此处描述的“2 SKLabelNode”投影技术,还通过添加另外三个“投影”,我已经能够获得一些可以接受的“轮廓”。
换句话说,一旦你有了底部的阴影,再添加三个。一个向顶部偏移,一个向右偏移,一个向左偏移——所以我在下面有四个“阴影”,主标签在顶部,总共五个 SKLabelNodes 只是为了创建这个轮廓效果。
在我的应用程序中,我必须为这个文本设置动画,所以我更进一步,从这五个标签创建了一个位图纹理,并从这个纹理创建了一个 SKSpriteNode,这让我可以删除五个原始标签节点,并制作动画位图版本。
还可能值得注意的是,通过从标签节点创建纹理会导致纹理模糊,我通过在创建纹理之前将标签节点的大小加倍来解决此问题,然后将生成的纹理大小减小50% .
我附上一张图片来向您展示结果。这可能不是最优雅的方法,但它似乎适用于我的特定情况。希望这可以帮助!
除了 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
) 消失!
例子:
let textNode = MKOutlinedLabelNode(fontNamed: "Helvetica", fontSize: 32)
textNode.borderColor = UIColor.blackColor()
textNode.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Center
textNode.fontColor = UIColor.blueColor()
textNode.outlinedText = "Test"
您还可以查看ASAttributedLabelNode。
这对我有用:
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)
关于大纲:
简短的回答:你已经完成了你的工作。
长答案:您确实为您完成了工作。
我们一直在一个项目上这样做,基本的方法是创建一个 UILabel 并将其渲染为进入精灵的纹理。
要将轮廓放到 UILabel 上,您可以使用:
如何让 UILabel 显示轮廓文本?
并将其渲染为 UIImage(您可以使用 [SKTexture textureWithImage:img] 制作纹理),使用此:
如何从 UILabel 创建图像?
这带来了一大堆问题,其中主要是缓慢、贪婪的渲染,这在很大程度上是通过尽可能将静态文本预渲染到文件来解决的。
由于字体往往需要精度,我认为您无法使用效果节点来实现这一点。回想起来,在走这条路之前,我会三思而后行。
我创建了一个继承自 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找到
Erica Sadun 曾经根据SKEffectNode
这里创建了一个阴影
我最近不得不创建她的 Swift4 版本ShadowLabelNode
:
https ://gist.github.com/Bersaelor/d6ea241278665173485e8aabafbe9047
使用面向对象!我已经将它实现为一个新组件,它是 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 应用程序中积极使用。亲切的问候,特德。