Is there really no way to style SKLabelNode? I mean beyond changing the font, and the color. I know I can do something like adding a drop shadow by creating a second SKLabelNode behind the first (already sort've hacky).. Creating images for my font would be terrible too for obvious reasons. It seems odd theres nothing you can do to break out of boring flat text.
I mean.. even the spritekit node count has a cool gradient style... how is THAT done?!
okay so here i am trying to recreate a gradient effect. I've tried every combination of blend mode, and multiple combinations of color, and colorBlendFactor.
alpha
multiply
add
here is the code
let testNode = SKLabelNode(text: "hey there")
testNode.fontSize = 30
testNode.color = SKColor.blueColor()
testNode.colorBlendFactor = 1
testNode.fontName = "Helvetica-Bold"
testNode.blendMode = SKBlendMode.Multiply
testNode.colorBlendFactor = 0.6
testNode.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
self.addChild(testNode)
It's pretty easy with a shader. Add a text file to your project called "TheShader.fsh":
void main()
{
float yPos = gl_FragCoord.y - labelBase;
float gradient = yPos / u_sprite_size.y; // ranges from 0 at base to 1 at top
vec4 color = SKDefaultShading(); // the current label color
color = vec4(gradient + color.r, gradient + color.g, gradient + color.b, color.a);
color.rgb *= color.a; // set background to alpha 0
gl_FragColor = color;
}
Now create an SKEffectNode in SKScene, set its shader to "TheShader", and add your label as a child of the effect node. The label will be drawn using a vertical gradient ranging from the label's fontColor at bottom to white at top.
override func didMoveToView(view: SKView)
{
makeGradientLabel("318 nodes 60.0 fps", labelPosition: CGPoint(x: CGRectGetMidX(frame), y: CGRectGetMidY(frame)))
}
func makeGradientLabel(labelText: String, labelPosition: CGPoint)
{
let myShader = SKShader(fileNamed: "TheShader")
let labelBase = SKUniform(name: "labelBase", float: Float(labelPosition.y))
myShader.addUniform(labelBase)
let effectNode = SKEffectNode()
effectNode.shader = myShader
effectNode.shouldEnableEffects = true
addChild(effectNode)
let theLabel = SKLabelNode(fontNamed: "Courier")
theLabel.fontSize = 36
theLabel.fontColor = SKColor.blueColor()
theLabel.text = labelText
theLabel.position = labelPosition
effectNode.addChild(theLabel)
}
If you move the label you'll need to update the labelBase uniform so the shader will know where it is:
labelBase.floatValue = Float(theLabel.position.y)
After a lot of trial and error, I got this working:
{
const CGFloat LABELFONTSIZE = 100;
SKColor* fontcolor = [SKColor redColor];
UIFont* font = [AppDelegate fontOfType:Fonttype_main size:LABELFONTSIZE]; // LABELFONTSIZE not used here but whatever.
SKLabelNode* label = [SKLabelNode labelNodeWithFontNamed:font.fontName];
label.fontColor = fontcolor;
label.verticalAlignmentMode = SKLabelVerticalAlignmentModeTop;
self.labelScore = label;
//label.zPosition = Z_HUD;
label.fontSize = LABELFONTSIZE;
self.score = 0;
const CGPoint LABELPOSITION = CGPointMake(self.size.width * 0.5, self.size.height);
label.position = LABELPOSITION;
#define USESHADER
#ifdef USESHADER
SKShader* myShader = [SKShader shaderWithFileNamed:@"TheShader"];
NSAssert(myShader, @"myShader was nil!");
SKEffectNode* effectNode = [SKEffectNode node];
effectNode.zPosition = Z_HUD;
effectNode.shader = myShader;
effectNode.shouldEnableEffects = YES;
[self addChild:effectNode];
[effectNode addChild:label];
#else
label.zPosition = Z_HUD;
[self addChild:label];
#endif
[label runAction:[SKAction repeatActionForever:[SKAction sequence:@[
[SKAction moveByX:0 y:-300 duration:3.0],
[SKAction moveByX:0 y:300 duration:3.0],
]]]];
}
TheShader.fsh:
void main()
{
float gradient = v_tex_coord.y;
//vec4 color = SKDefaultShading(); // the current label color THIS DOES NOT WORK ON IOS 9.2 AND EARLIERISH (MAYBE IT DOES ON IOS 8) WORKS ONLY ON IOS 9.3 BETA AT THIS MOMENT!
vec4 color = texture2D(u_texture, v_tex_coord);
color = vec4(color.r + gradient, color.g + gradient, color.b + gradient, color.a);
color.rgb *= color.a; // set background to alpha 0
gl_FragColor = color;
}
It's based on Loengard's answer, but does not use any uniforms. A few of the stuff inside the shader did/does not work on a number of iOS 9 versions, including the latest iOS 9.3 beta as of now (20160115). This code above works well, it doesn't even care about the position of the label on screen; I animate the label up/and down to confirm this.
There is no method or property of SKLabelNode that will enable you to achieve the gradient style. As noted in the link in the comments, SpriteKit does have a SKBitmapFont private class, but that's not going to help you.
You can either roll your own solution or try glyph designer : https://71squared.com/glyphdesigner
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With