How to change a SKSpriteNode saturation? - Swift - swift

I develop a game and I'd like to have the background change its saturation over a certain amount of time, but have no idea how to do it... So here's my code:
var bg = SKSpriteNode()
bg.size = frame.size
bg.position = CGPoint(x: frame.midX, y: frame.midY)
bg.zPosition = -1000
bg.texture = SKTexture(imageNamed: "background")
bg.alpha = 0.5
addChild(bg)
Thanks a lot !

You can add you background as a child node of a SKEffectNode then set create a color controls filter as the effect node filter. Setting the kCIInputSaturationKey to values less than one will cause the background image to be desaturated, greater than one will cause the background to become more saturated.
var effectNode = SKEffectNode()
effectNode.addChild(bg)
effectNode.filter = CIFilter(name: "CIColorControls")
effectNode.filter?.setValue(0.1, forKey: kCIInputSaturationKey)

Related

Render text with SKRenderer

I initialized SKRenderer in my project to use it alongside of metal. Although I'm not sure that I did it correctly, I need to know how I can render a simple 2D text with it?
For example, here is how we can draw a text with SKLabelNode, do we have anything like it for SKRenderer?
thank you so much
let winner = SKLabelNode(fontNamed: "Chalkduster")
winner.text = "You Win!"
winner.fontSize = 65
winner.fontColor = SKColor.red
winner.position = CGPoint(x: 100, y: 100)
view.addChild(winner)
The first thing you need to do is initialize the scene.
var renderer: SKRenderer
var skScene: SKScene
in your init function:
renderer = SKRenderer(device: device)
// iphone 11 portrait
skScene = SKScene(size: CGSize(width: 1125, height: 2436))
renderer.scene = skScene
let winner = SKLabelNode(fontNamed: "Chalkduster")
winner.text = "You Win!"
winner.fontSize = 65
winner.fontColor = SKColor.red
winner.position = CGPoint(x: 1125 / 2, y: 2436 / 2)
skScene.addChild(winner)
and finally in your render function:
renderer.render(withViewport: viewport, renderCommandEncoder: renderEncoder, renderPassDescriptor: renderPassDescriptor, commandQueue: commandQueue)
renderEncoder.endEncoding()
but keep in mind ui layer (SKRenderer) should be rendered in the last pass.

Setting a repeated background in an SKScene

I am building an iOS game using the SpriteKit library. I have a background of stars. However, I don't want to upload a static image, because it might scale incorrectly depending on the device size. So I got a png that I repeat over to fill up the screen. I tried doing this:
self.backgroundColor = UIColor(patternImage: UIImage(named: "background.png")!);
However, it only sets the background to a black color. Does anyone have any suggestions on how to do this?
I think this will help you, Firstly set the background using the below code:
for index in 0..<2 {
let bg = SKSpriteNode(imageNamed: "Your image name")
bg.position = CGPoint(x: index * Int(bg.size.width), y: 0)
bg.anchorPoint = CGPoint(x: 0, y: 0)
bg.name = "background"
self.addChild(bg)
}
and then use this code to move the background:
self.enumerateChildNodes(withName: "background", using: {(node, stop) -> Void in
if let bg = node as? SKSpriteNode {
bg.position = CGPoint(x: bg.position.x - 3.0, y: bg.position.y)
if bg.position.x <= -bg.size.width {
bg.position = CGPoint(x: bg.position.x + bg.size.width * 2, y: bg.position.y)
}
}
})

Converting Multiple Sprite Images into One

In an app I'm testing out, I'm using a gradient image as a background (590kb in size). I have the ability of breaking this image into 0.5 pixel vertical strips (19kb) and having this image repeat itself (1334 times) to create the same larger background image. I have 20 different background images total so the app will be 11.8mb vs 380kb in storage usage.
I don't like the idea of having 1334 sprites, but I do like the idea of using less storage. So, is there a way of flatting the 1334 images into one sprite? Not sure if this make sense, but any push in the right direction would be appreciated.
You don't have to use image at all if you want to have a gradient. Take a look at this:
let context = CIContext()
if let filter = CIFilter(name: "CILinearGradient")
{
filter.setDefaults()
let startColor = CIColor(color: .gray)
let endColor = CIColor(color: .purple)
let startVector = CIVector(x: frame.width, y: 0)
let endVector = CIVector(x: frame.width, y: frame.height)
filter.setValue(startVector, forKey: "inputPoint0")
filter.setValue(endVector, forKey: "inputPoint1")
filter.setValue(startColor, forKey: "inputColor0")
filter.setValue(endColor, forKey: "inputColor1")
if let outputImage = filter.outputImage {
if let croppedImage = context.createCGImage(outputImage, from: CGRect(origin: CGPoint.zero, size: frame.size)){
let background = SKSpriteNode(texture: SKTexture(cgImage: croppedImage))
addChild(background)
background.zPosition = -20
}
}
}
Repeating an image horizontally or vertically to achieve the same effect is possible. That would require creating texture from a container node using something like this. Still, IMO, you may want skip that and do gradient programatically. And certainly I would stay away of having many nodes which act as a background. That would be silly :)

Rotate a SKShapeNode with texture

I'm trying to rotate an SKShapeNode with a texture, but it's not working. Basically, I have a circle with a texture and I'm trying to make it rotate using the same way I have done with an SKSpriteNode:
let spin = SKAction.rotateByAngle(CGFloat(M_PI/4.0), duration: 1)
The problem is that the circle is rotating, but not the texture. I can check this by using this code:
let wait = SKAction.waitForDuration(0.5)
let block = SKAction.runBlock({
print(self.circle.zRotation)
})
let sequence = SKAction.sequence([wait, block])
self.runAction(SKAction.repeatActionForever(sequence))
This is the code I have for creating the SKShapeNode:
let tex:SKTexture = SKTexture(image: image)
let circle = SKShapeNode(circleOfRadius: 100 )
circle.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2 + 200)
circle.strokeColor = SKColor.clearColor()
circle.glowWidth = 1.0
circle.fillColor = SKColor.whiteColor()
circle.fillTexture = tex
self.addChild(circle)
// Runing the action
circle.runAction(spin)
Please help. Thanks in advance!
PS: I know that using an SKSpriteNode would be better but my goal is to place a square image in a circular frame and I figured that using an SKShapeNode would be perfect. If anyone know how to create a circular SKSpriteNode, feel free to post it in the answers section! :)
This is what I'm trying to achieve (with the capability of rotating it):
You can achieve what you want by using SKCropNode and setting its mask property to be a circle texture:
override func didMoveToView(view: SKView) {
let maskShapeTexture = SKTexture(imageNamed: "circle")
let texture = SKTexture(imageNamed: "pictureToMask")
let pictureToMask = SKSpriteNode(texture: texture, size: texture.size())
let mask = SKSpriteNode(texture: maskShapeTexture) //make a circular mask
let cropNode = SKCropNode()
cropNode.maskNode = mask
cropNode.addChild(pictureToMask)
cropNode.position = CGPoint(x: frame.midX, y: frame.midY)
addChild(cropNode)
}
Let's say that picture to mask has a size of 300x300 pixels. The circle you are using as a mask, in that case, has to have the same size. Means the circle itself has to have a radius of 150 pixels (diameter of 300 pixels) when made in image editor.
Mask node determines the visible area of a picture. So don't make it too large. Mask node has to be a fully opaque circle with transparent background.

Swift. Masking a SKTexture on top of a SKSpriteNode

Okay so I have som problems, trying to mask a SKTexture on top op a SKSpriteNode. I've been looking in to SKCropNode, but cant figure it out.
(I'm kinda new to this)
How can i mask this SKTexture: (This is the image called "Mask")
on top of this SKSpriteNode:
so its going to turn out like this:
I tried this, but nothing showed up:
picture.size = CGSize(width: menuLine.frame.height, height: menuLine.frame.height)
picture.zPosition = 10
let cropNode = SKCropNode()
cropNode.addChild(picture)
cropNode.maskNode = SKSpriteNode(imageNamed("Mask")
self.addChild(cropNode)
cropNode.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
cropNode.zPosition = 10