SKShapeNode inside another one, limited by parent bounds - swift

All right, so let's say I have two SKShapeNodes (or any SKNode related object), one is a circle, and the other is a square. I'm just trying to put the square inside the circle so it looks like this:
However, if I simply add the Square Shape Node inside the Circle Shape Node, as it's child, it just ends up looking like this:
How do I limit the Circle's children to the circle's bounds? For those images, I basically created a new project with the default GameKit template, and it's GameScene.swift code is basically this:
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var circleNode = SKShapeNode()
var squareNode = SKShapeNode()
override func didMove(to view: SKView) {
// Setup Shape Nodes:
circleNode = SKShapeNode(circleOfRadius: 100)
circleNode.fillColor = .blue
squareNode = SKShapeNode(rectOf: CGSize(width: 200, height: 200))
squareNode.fillColor = UIColor.gray.withAlphaComponent(0.5)
// Positioning Shape Nodes:
circleNode.position = CGPoint(x: 0, y: 0)
squareNode.position = CGPoint(x: 0, y: -circleNode.frame.height/2) // At the middle of Circle Node!
// Inserting Circle Node in the Game Scene:
self.addChild(circleNode)
// Inserting Square Shape Node in the Circle Node:
circleNode.addChild(squareNode)
}
}
How can I accomplish this behavior? Any help would be greatly appreciated!

Related

Using particle effects or animated sks files to create filled letters

I have one .png image of a single star. I'd like to use this image to create animated star-filled letters. This is what I'd like to do (but the stars would be sort of animated within this, which I imagine can be done with particle effects):
Could I do this by using potentially several sks files for each letter and then loading them into one larger scene? In addition, if I just wanted to fill the label node with a static texture of several stars, is there an alternate way of doing this?
Not ideal, but an easy to achieve:
override func didMove(to view: SKView) {
if let nodeToMask = SKEmitterNode(fileNamed: "firelfies") {
backgroundColor = .black
let cropNode = SKCropNode()
cropNode.position = CGPoint(x: frame.midX, y: frame.midY)
cropNode.zPosition = 1
let mask = SKLabelNode(fontNamed: "ArialMT")
mask.text = "MASK"
mask.fontColor = .green
mask.fontSize = 185
cropNode.maskNode = mask
nodeToMask.position = CGPoint(x: 0, y: 0)
nodeToMask.name = "character"
cropNode.addChild(nodeToMask)
addChild(cropNode)
}
}
I think the code is self-explanatory, but basically, you just use text as a mask of a crop node, and you mask an emitter. Here is the result:
The thing with this implementation is that sparkles don't go outside of the letter bounds.

SpriteKit: Coloring the Background

i still try to learn Swift and SpriteKit and i have a new question.
So i am following this Tutorial/Video: Noise Field
My project now looks like this: My Project
I have 100 Particle Objects moving around and i want to blend some color of the particles to the white background. Inside the tutorial it is quiet easy. You just create the Background once, and inside the draw function (in SpriteKit this would be the update() function) you give your objects an alpha value like 0.1.
SpriteKit works quiet different. If i change the alpha value under draw my Particles are now almost hidden, but the color is not being "drawn" on the background.
I know this is because SpriteKit works different then the p5 library for javascript. But i wonder how i could get the same effect inside SpriteKit..
So inside the update function i have 2 loops, one for columns and one for rows. I have x columns and y rows - and for each "cell" i create a random CGVector. Now my Particles are moving around based on the CGVector of the cell which is the nearest to the Particles position.
My Particle Class looks like this:
class Particle: SKShapeNode{
var pos = CGPoint(x: 0, y: 0)
var vel = CGVector(dx: 0, dy: 0)
var acc = CGVector(dx: 0, dy: 0)
var radius:CGFloat
var maxSpeed:CGFloat
var color: SKColor
And i have a function which looks like this to show the Particles:
func show(){
self.position = self.pos
let rect = CGRect(origin: CGPoint(x: 0.5, y: 0.5), size: CGSize(width: self.radius*2, height: self.radius*2))
let bezierP = UIBezierPath(ovalIn: rect)
self.path = bezierP.cgPath
self.fillColor = self.color
self.strokeColor = .clear
}
And in the update function i have this loop:
for particle in partikelArr{
particle.updatePos()
particle.show()
}
How could i now "colorize" the white background or "draw" my particle on the background based on the particles position, color, shape and size?
Thanks and best regards
EDIT:
So i know create for each particle a new SKShapeNode inside the update function, so this works and it looks like the Particles have colorized the background:
This was created like this inside the update function:
for particle in partikelArr{
let newP = SKShapeNode(path: particle.path!)
newP.position = particle.pos
newP.fillColor = particle.farbe
newP.strokeColor = .clear
newP.zPosition = 1000
newP.alpha = 0.1
self.addChild(newP)
}
But i do not want to create SKShapeNodes for each Particle (on the screenshot i have used 5 Particles, after some seconds i already have over 800 nodes on the scene). I would like to let my 100 Particles really "draw" their Shape and Color on the white Background node.

SpriteKit: Add a node to view?

I'm new to Xcode 7, how do I add a black node in SpriteKit?
Can anyone point me in the right direction or link me up with any tutorials please? Thank you
You want to create a new SKSpriteNode object, and add it to the view
class GameScene: SKScene {
var node: SKSpriteNode?
override func didMoveToView(view: SKView) {
let node = SKSpriteNode(imageNamed: "BlackNode.png")
node.position.x = self.size.width / 2
node.position.y = self.size.height / 2
addChild(node)
}
}
So in your GameScene class (or whatever SKScene class you are using), this creates a SKSpriteNode that is the image of whatever "BlackNode.png" is, and sets its position to the center of the screen, and adds it to scene
Assuming your question is asking how to add an all black node to the scene, try this:
override func didMoveTo(view: SKView) {
let node = SKSpriteNode(color: UIColor.black, size: CGSize(width: 100, height: 100)) // Declare and initialize node
addChild(node) // Function that adds node to scene
}
This uses the SKSpriteNode initializer init(color: UIColor, size: CGSize), which you would pass a color for the node and size. This is then used to create a rectangle, while the nodes texture property remains nil.
Note that in this example, no position is explicitly chosen, so the default (0,0) is chosen (centre of scene if scene anchorPoint is 0.5,0.5)
To get a further understanding of scenes vs views and SpriteKit vs UIKit (which I think is where you're having trouble) check out this answer: SpriteKit vs UIKit

SpriteKit convertPointToView / convertPoint

Question How do I get the purple square to stay anchored at the bottom left of the screen regardless of the camera position?
Details I have an SKScene named colorScene that has a camera node and two shape nodes - one blue and one purple square. The camera is constrained to the blue square which is positioned at 0,0:
Now, say I want to position the purple square at the bottom left of the screen. And I want it to stay there no matter where the camera goes. First, I would make the purple square a child of the camera node. But then what? If I position the purple square at 0,0, strangely, it's in the middle of the screen. (Shouldn't the camera node be the entire screen area?) And if I try convertPoint to go from the camera node to the scene coordinates:
purpleNode?.position = convertPoint(CGPoint(x: 0, y: 0), toNode: cameraNode!)
...things get even more mysterious:
From the Apple docs:
The scene is rendered so that the camera node’s origin is placed in the middle of the scene.
This should explain what you experienced
If I position the purple square at 0,0, strangely, it's in the middle of the screen. (Shouldn't the camera node be the entire screen area?)
Solution
Since we want to place purple on the bottom-left of the screen, we should start with the coordinate related to the view
let bottomLeftOfView = CGPoint(x: 0, y: view.frame.height)
Next we need to convert these coordinate from the view to the scene
purple.position = convertPointFromView(bottomLeftOfView)
This is the full code
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
super.didMoveToView(view)
let camera = SKCameraNode()
self.camera = camera
addChild(camera)
let purple = SKSpriteNode(imageNamed: "square")
purple.color = SKColor.purpleColor()
purple.colorBlendFactor = 1
let bottomLeftOfView = CGPoint(x: 0, y: view.frame.height)
purple.position = convertPointFromView(bottomLeftOfView)
camera.addChild(purple)
}
}
Purple and anchorpoint
Only a quarter of the purple sprite is inside the screen. This because its anchorpoint is (0.5, 0.5): the center. So we just told SpriteKit to place the center of purple to the corner of the screen.
In order to have purple entirely into the screen we just need to tell SpriteKit to use use the bottom left corner of purple as anchorpoint
purple.anchorPoint = CGPointZero
This is the final full code
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
super.didMoveToView(view)
let camera = SKCameraNode()
self.camera = camera
addChild(camera)
let purple = SKSpriteNode(imageNamed: "square")
purple.color = SKColor.purpleColor()
purple.colorBlendFactor = 1
purple.anchorPoint = CGPointZero
let bottomLeftOfView = CGPoint(x: 0, y: view.frame.height)
purple.position = convertPointFromView(bottomLeftOfView)
camera.addChild(purple)
}
}

Lag when trying to implement parallax effect in swift (spritekit)

I am trying to create game in SpriteKit with parallax effect, but when I implement my method, my hero lags (quickly shakes) from time to time (no pattern observed)...
I wrote this simple code that illustrates the method and also contains the same problem.
The hero should stay in the center of the screen and only his position relative to his parent (foreground) should change. But it lags (quickly shakes for a really short moment) every now and then. I also noticed that when I run the game, the hero sinks down very, very slowly a few pixels (maybe 5-10) before it starts holding its position after ~15 sec.
I can't figure out what is causing this behavior. Any help would be appreciated. I am testing on IPhone 6.
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
let hero = SKSpriteNode(imageNamed: "hero")
let foreground = SKNode()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(size: CGSize) {
super.init(size: size)
physicsWorld.gravity = CGVector(dx: 0.0, dy: -0.5)
physicsWorld.contactDelegate = self
// anchor point of scene is at (x: 0.5, y: 0.5)
hero.position = CGPoint(x: 0, y: 0)
hero.physicsBody = SKPhysicsBody(rectangleOfSize: hero.size)
hero.physicsBody?.dynamic = true
hero.physicsBody?.allowsRotation = false
addChild(foreground)
foreground.addChild(hero)
}
override func update(currentTime: NSTimeInterval) {
foreground.position = CGPoint(x: 0, y: -(hero.position.y))
}
}
// I need the foreground to move in opposite direction so I can add stars,
// monsters, etc while keeping the player in the view... Update method does
// this: hero is pulled down by gravity so his y position would be -1 pixel
// relative to foreground but I assign foreground the opposite y-position of
// hero (+1) and since hero's position relative to foreground is -1, he should
// be positioned at y-position = 0 which, in this code example, should create
// an illusion that he is positioned at the center and doesn't move