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
Since iOS 11 SKLabelNode has attributedText property. You need to specify strokeColor
, strokeWidth
and don't forget font
and foregroundColor
.
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)
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!
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 ...
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.
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