Swift. Masking a SKTexture on top of a SKSpriteNode - swift

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

Related

SKCropNode doesn't display anything

I can't get SKCropNode to cooperate. I've played with this for HOURS I've copied verbatim hackingwithswifts guide and the only difference being my image and it will not work. So then I dumbed it down for myself with the code below and it still doesn't work.
I've tried the guide directly from hacking with swift and it didn't work. I copied code directly from apple documentation that also didn't work. I've wasted wayyyy too much time on the simple task of cropping an image.
import SpriteKit
import GameplayKit
import UIKit
class ProcGenPlanet: SKScene{
//Background
//let background = SKSpriteNode()
var square = SKSpriteNode()
override func didMove(to view: SKView) {
square = SKSpriteNode(imageNamed: "redSquare")
square.size = CGSize(width: 1000, height: 1000)
square.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2)
let mask = SKSpriteNode(color: SKColor.black, size: CGSize(width: 100, height: 100))
let cropNode = SKCropNode()
cropNode.maskNode = mask
cropNode.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2)
cropNode.addChild(square)
}
}
I am creating 1000x1000 red square. The whole image is red. Then I am trying to crop it to 100x100 with the following code but instead NOTHING shows up.

SpriteKit: unwanted stretching of sprite when resizing/scaling

I've seen similar questions before but seems that no clear solution is provided. Currently I have a SKScene with child, contained by a SKView. Note: I'm not using a Game project; instead, I'm using the SKView in a normal UIView, and just add SKView as the subview of the UIView. The sprite itself is a small image, and it only occupies a certain portion in the middle-bottom part of the whole frame. The code looks something like this:
let imageView = SKView()
imageView.frame = CGRect(x: ..., y: ..., width: ..., height: ...) //all are predefined constants
let sprite = SKSpriteNode(texture: SKTexture(imageNamed: "image"))
sprite.position = CGPoint(x: imageView.frame.width * 0.5, y: imageView.frame.height * 0.5) // so it's positioned in the center
let scene = SKScene(size: imageView.frame.size) // also tried with sprite.size, but not working
scene.addChild(sprite)
scene.scaleMode = .aspectFit
imageView.presentScene(scene)
self.frame.addSubview(imageView)
Now the problem is the sprite is not in its original shape; it's stretched along the vertical axis. I tried changing the scaleMode with all 5 choices: .fill / .aspectFill / .aspectFit / .resizeFill / none, but none of them give the sprite its original shape/ratio. I've also tried changing the constants for the imageView's frame, but that only cuts the sprite (if imageView.frame.height is decreased). So may I know how to address this issue?
Your code works fine as written, so the problem is likely elsewhere. I modified it a little bit so you can test it out in a Playground. Just make a new Playground and copy and paste. You'll also have to drag in an image for your sprite.
import SpriteKit
import PlaygroundSupport
// create the outer UIView and show it on the playground
let outerView = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
PlaygroundPage.current.liveView = outerView
// create the SKView and add it to the outer view
let imageView = SKView(frame: CGRect(x: 25, y: 25, width: 250, height: 250))
outerView.addSubview(imageView)
// create the scene and present it
var scene = SKScene(size: imageView.frame.size)
imageView.presentScene(scene)
// create the sprite, position it, add it to the scene
let sprite = SKSpriteNode(texture: SKTexture(imageNamed: "worf.jpg"))
sprite.position = CGPoint(x: imageView.frame.width * 0.5, y: imageView.frame.height * 0.5)
scene.scaleMode = .aspectFit
scene.addChild(sprite)
Here's the result:
No stretching! So your issue is probably related to the UIView you're placing it in. For example if you add:
outerView.transform = CGAffineTransform(scaleX: 1, y: 2)
Now the image is stretched as you describe. Take a look at your containing view and everything above it.

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.

How to contain SKEmitterNode particles in parent Node?

I would like to add a SKEmitterNode to SKNode but have its particles stay inside the parent node's frame. Kinda like clipsToBounds property on UIView.
Example: the particles from the emitter should not leave the black square SKSpriteNode:
You could do it with SKCropNode. Like this:
if let particles = SKEmitterNode(fileNamed: "rain.sks") {
let cropNode = SKCropNode()
cropNode.position = CGPoint(x: CGRectGetMidX(frame), y: CGRectGetMidY(frame))
cropNode.zPosition = 3
cropNode.maskNode = SKSpriteNode(color: SKColor.blackColor(), size: CGSize(width: 150, height: 150))
cropNode.addChild(particles)
addChild(cropNode)
}
Unfortunately this works only on iOS8... When you try to add an emitter into crop node in iOS9, you will probably run into some issues, eg. nothing will be rendered and fps drop may occur. And this is already known issue.
Like it's said in that link, instead of particles being rendered, nothing actually happens. Personally, I haven't experienced fps issues , but particles are definitely not rendered.
A workaround would be to add a node which will hold an emitter, and then mask that container node. So, let's add an SKSpriteNode to make that black background like from your example. Let's call it background:
if let particles = SKEmitterNode(fileNamed: "rain.sks") {
let cropNode = SKCropNode()
cropNode.position = CGPoint(x: CGRectGetMidX(frame), y: CGRectGetMidY(frame))
cropNode.zPosition = 3
let blackNode = SKSpriteNode(color: .blackColor(), size: CGSize(width: 200, height: 200))
blackNode.addChild(particles)
cropNode.maskNode = SKSpriteNode(color: SKColor.blackColor(), size: CGSize(width: 200, height: 200))
cropNode.addChild(blackNode)
addChild(cropNode)
}

How to create a rectangle in Sprite kit using Swift

I'm trying to create a rectangle using swift on Sprite kit, since the rectangle needs to be used as an object in the scene, i assumed that i needed to create a SkSpriteNode, and them give it a size, but it did not worked, this is how i did it:
var barra = SKSpriteNode()
barra.name = "bar"
barra.size = CGSizeMake(300, 100)
barra.color = SKColor.whiteColor()
barra.position = CGPoint(x: 100, y: 100)
self.addChild(barra)
Adding barra to the screen does not change the node counting.
Any help will be appreciated!
You may want to use a SKShapeNode, like this:
var barra = SKShapeNode(rectOfSize: CGSize(width: 300, height: 100))
barra.name = "bar"
barra.fillColor = SKColor.whiteColor()
barra.position = location
self.addChild(barra)
Here's Apple's documentation on SKShapeNode.
The way I was creating the rectangle was not the best, but the problem was the position I was inserting it on the game. This is how I've fixed it:
var barra = SKSpriteNode(color: SKColor.blackColor(), size: CGSizeMake(200, 200))
barra.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
barra.zPosition = 9 // zPosition to change in which layer the barra appears.
self.addChild(barra)