Making Sklabelnode as a Crop Node of Skshapenode

How to crop out a SKLabelNode from a SKShapeNode?

If you invert your thinking, this will be much easier.

Put the Red layer at the back/bottom. Lowest zPosition. Let's say -1.0 for this example.

Put the picture on top of this, at a zPosition of 0.0

Put the letter above, at a zPostion of 1.0

So, from the screen of the iPhone, it's like this:

  • Screen
  • Letter
  • Picture
  • Red BG

You want to use the letter to mask out the picture.

Having done that, whenever you move the letter, it reveals the contents beneath itself, from the picture. Everything else is RED.

How to rotate SKLabelNode in company with its parent SKShapeNode?

You need to set your friction to a number other than 0.

Also, concerning the shape node performance:

look at the draw count at the bottom of 50 shapes:

Sample Image

for _ in 1...50 {
let x = arc4random_uniform(UInt32(frame.maxX));
let xx = CGFloat(x) - size.width/4

let y = arc4random_uniform(UInt32(frame.maxY))
let yy = CGFloat(y) - size.width/4

let shape = SKShapeNode(circleOfRadius: 50)
shape.strokeColor = .blue
shape.lineWidth = 1
shape.position = CGPoint(x: xx, y: yy)
addChild(shape)
}

But now compare that to this image of only 2 draws with only a few lines of refactoring:

func addFiftySprites() {

let shape = SKShapeNode(circleOfRadius: 50)
shape.strokeColor = .blue
shape.lineWidth = 1

let texture = SKView().texture(from: shape)

for _ in 1...50 {
let x = arc4random_uniform(UInt32(frame.maxX));
let xx = CGFloat(x) - size.width/4

let y = arc4random_uniform(UInt32(frame.maxY))
let yy = CGFloat(y) - size.width/4

let sprite = SKSpriteNode(texture: texture)
sprite.position = CGPoint(x: xx, y: yy)

addChild(sprite)
}
}

Sample Image


The magic here is using let texture = SKView().texture(from: <SKNode>) to convert the shape to a sprite :) let sprite = SKSpriteNode(texture: texture)

Crop SKTexture with SKLabel text

Knight0fDragon have reason in his comment, this is a good suggestion. There is another solution you can do without textureFromNode.
You can prepare your cropNode with the background and the label, then make another background clone with the button and your cropNode over all:

import SpriteKit
class GameScene: SKScene {
override func didMove(to view: SKView) {
let background = SKSpriteNode.init(imageNamed: "background.png")
background.zPosition = 1
let background2 = background.copy() as! SKSpriteNode
//label
let titleLabel = SKLabelNode(fontNamed: "AvenirNext-Bold")
titleLabel.fontSize = 150
titleLabel.fontColor = SKColor.black
titleLabel.text = "RATE"
titleLabel.horizontalAlignmentMode = .center
titleLabel.zPosition = 5
titleLabel.blendMode = .subtract
//cropNode
let cropNode = SKCropNode()
cropNode.addChild(background)
cropNode.maskNode = titleLabel
self.addChild(cropNode)
cropNode.zPosition = 5
//button
let button = SKShapeNode(rect: CGRect(x: -300, y: -50, width: 600, height: 200), cornerRadius: 100)
button.zPosition = 4
button.fillColor = SKColor.white
self.addChild(background2)
self.addChild(button)
}
}

Image used:
Sample Image

Output:

Sample Image

Another background to test:

Sample Image

Output 2:

Sample Image

Is it possible to use a circle (SKShapeNode) as a mask in Sprite Kit?

After much swearing, scouring the web, and experimentation in Xcode, I have a really hacky fix.

Keep in mind that this is a really nasty hack - but you can blame that on Sprite Kit's implementation of SKShapeNode. Adding a fill to a path causes the following:

  • adds an extra node to your scene
  • the path becomes unmaskable - it appears 'over' the mask
  • makes any non-SKSpriteNode sibling nodes unmaskable (e.g. SKLabelNodes)

Not an ideal state of affairs.

Inspired by Tony Chamblee's progress timer, the 'fix' is to dispense with the fill altogether, and just use the stroke of the path:

SKCropNode *cropNode = [[SKCropNode alloc] init];

SKShapeNode *circleMask = [[SKShapeNode alloc ]init];
CGMutablePathRef circle = CGPathCreateMutable();
CGPathAddArc(circle, NULL, CGRectGetMidX(self.frame), CGRectGetMidY(self.frame), 50, 0, M_PI*2, YES); // replace 50 with HALF the desired radius of the circle
circleMask.path = circle;
circleMask.lineWidth = 100; // replace 100 with DOUBLE the desired radius of the circle
circleMask.strokeColor = [SKColor whiteColor];
circleMask.name=@"circleMask";

[cropNode setMaskNode:circleMask];

As commented, you need to set the radius to half of what you'd normally have, and the line width to double the radius.

Hopefully Apple will look at this in future; for now, this hack is the best solution I've found (other than using an image, which doesn't really work if your mask needs to be dynamic).

SKCropNode fails when I add extra SKNode children in hierarchy

SKShapeNode is bugged, best to avoid it at all costs. Use it to create your shapes, then convert it to a texture for use with SKSpriteNode



Related Topics



Leave a reply



Submit