SKSpriteNodes Colliding and sticking on top each other - swift

My SKSpritekit nodes are stacking on top each other and sticking to each other. I have added SKSprite nodes via the sks file and programmatically.
let texture = SKTexture(image: #imageLiteral(resourceName: "cone"))
trCone = SKSpriteNode(texture: texture, normalMap: texture)
//trCone?.texture = SKTexture(image: #imageLiteral(resourceName: "cone"))
trCone?.size = CGSize(width: 60, height: 65)
trCone?.position = CGPoint(x: 153, y: 267)
trCone?.zPosition = 15
trCone?.name = trainingStuff.text
trCone?.physicsBody = SKPhysicsBody(texture: SKTexture(image: #imageLiteral(resourceName: "cone")), size: CGSize(width: 60, height: 65))
trCone?.physicsBody?.allowsRotation = false
trCone?.physicsBody?.isDynamic = false
trCone?.physicsBody?.categoryBitMask = .zero
trCone?.physicsBody?.collisionBitMask = .zero
myTrainigArr?.append(trCone!)
self.myScene!.addChild(trCone!)
This is how I add the nodes. I would like them to overlap each other and pass through each other without any collisions but this is the outcome. When I try to move the nodes after they collide one is now stuck on top of the other. Any suggestions will be appreciated.

Related

Create Wall / Barrier Using SKSpriteNode physicsBody

I have a separate "Floor" class in my SKSpriteKit application. When I first created this class, I had a barrier around the whole frame using
self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
but that was actually stopping SKSpriteNodes from entering from the top of the screen so now I'm trying to figure out how I can create a left, right and bottom of the frame wall but not the top. This is so I can avoid one of my SKSpriteNodes at the bottom of the screen (still viewable by users) that moves left and right from leaving the display. I'm trying below which is building as if it's going to work but then when I start up the game I don't see the the walls? I'm not too sure what I'm doing wrong, I have
skView.showsPhysics = true
import Foundation
import SpriteKit
class Floor: SKNode {
override init() {
super.init()
let leftWall = SKSpriteNode(color: UIColor.brown, size: CGSize(width: 100, height: frame.height))
leftWall.position = CGPoint(x: 100, y: 100)
leftWall.physicsBody = SKPhysicsBody(rectangleOf: leftWall.size)
leftWall.physicsBody!.isDynamic = false
self.addChild(leftWall)
let rightWall = SKSpriteNode(color: UIColor.brown, size: CGSize(width: 100, height: frame.height))
rightWall.position = CGPoint(x: 200, y: 200)
rightWall.physicsBody = SKPhysicsBody(rectangleOf: rightWall.size)
rightWall.physicsBody!.isDynamic = false
self.addChild(rightWall)
// Set the bit mask properties
self.physicsBody?.categoryBitMask = balloonCategory
self.physicsBody?.contactTestBitMask = nailDropCategory
//self.physicsBody?.collisionBitMask = balloonCategory
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemted")
}
}
Gravity is affecting your walls, so they are forever falling into oblivion.
When you created your edge loop, you did not need to worry about this because edge loops are always static because it has no volumne
Now you are using volume based bodies, so you need to account for things like gravity and other forces affecting your bodies.
To have your body ignore these forces, simply set isDynamic = false
let leftWall = SKSpriteNode(color: UIColor.brown, size: CGSize(width: 100, height: frame.height))
leftWall.position = CGPoint(x: 100, y: 100)
leftWall.physicsBody = SKPhysicsBody(rectangleOf: leftWall.size)
leftWall.physicsBody!.isDynamic = false
self.addChild(leftWall)
let rightWall = SKSpriteNode(color: UIColor.brown, size: CGSize(width: 100, height: frame.height))
rightWall.position = CGPoint(x: 200, y: 200)
rightWall.physicsBody = SKPhysicsBody(rectangleOf: rightWall.size)
rightWall.physicsBody!.isDynamic = false
self.addChild(rightWall)

Child node not keeping same physicsBody when added to parent

Using the Xcode SpriteKit Scene editor I have a few objects added to the scene as "obstacles." I like to animate them across the screen. They are not dynamic. To make things easier I thought to add them to an obstacleParent node and just animate that one object. The problem is that adding the obstacles to a parent totally screws up their physics bodies. Meaning the obstacle physics bodies do not match the outline of the sprite.
I'm not sure if it is a bug in the Scene editor, but adding the physics bodies programmatically yields results as expected.
Some interesting things worth noting are:
the physicsBodies moved with the parent regardless of if they were not Dynamic or not.
I could not get them to overlap each other until I made them all have the same contactTestBitMask
It is difficult to tell in the screen shot but all 3 children kept their physics shapes
If the parent has a physics body and an physics impulse is applied to it, only the parent moves. However setting the position of the parent programmatically moves the parent and child nodes
testObject = SKSpriteNode(texture: nil, color: .greenColor(), size: CGSize(width: 100, height: 100))
testObject.zPosition = Layer.Controls.rawValue
testObject.position = CGPoint(x: self.size.width / 2, y: self.size.height / 2)
// testObject.physicsBody = SKPhysicsBody(circleOfRadius: testObject.width / 2)
// testObject.physicsBody!.dynamic = true
// testObject.physicsBody!.affectedByGravity = false
// testObject.physicsBody!.allowsRotation = true
addChild(testObject)
let testerObject = SKSpriteNode(texture: nil, color: .clearColor(), size: CGSize(width: 100, height: 100))
testerObject.zPosition = Layer.Controls.rawValue
testerObject.position = CGPoint(x:50, y: 50)
testerObject.physicsBody = SKPhysicsBody(circleOfRadius: testerObject.width / 2)
testerObject.physicsBody!.affectedByGravity = false
testerObject.physicsBody!.dynamic = true
testerObject.physicsBody!.allowsRotation = true
testerObject.physicsBody!.collisionBitMask = 0
testerObject.physicsBody!.contactTestBitMask = 0
testObject.addChild(testerObject)
let testerObject2 = SKSpriteNode(texture: nil, color: .clearColor(), size: CGSize(width: 100, height: 100))
testerObject2.zPosition = Layer.Controls.rawValue
testerObject2.position = CGPoint(x:-50, y: -50)
testerObject2.physicsBody = SKPhysicsBody(circleOfRadius: testerObject.width / 2)
testerObject2.physicsBody!.affectedByGravity = false
testerObject2.physicsBody!.dynamic = true
testerObject2.physicsBody!.allowsRotation = true
testerObject2.physicsBody!.collisionBitMask = 0
testerObject2.physicsBody!.contactTestBitMask = 0
testObject.addChild(testerObject2)
let testerObject3 = SKSpriteNode(texture: nil, color: .clearColor(), size: CGSize(width: 100, height: 100))
testerObject3.zPosition = Layer.Controls.rawValue
testerObject3.physicsBody = SKPhysicsBody(circleOfRadius: testerObject.width / 2)
testerObject3.physicsBody!.affectedByGravity = false
testerObject3.physicsBody!.dynamic = true
testerObject3.physicsBody!.allowsRotation = true
testerObject3.physicsBody!.collisionBitMask = 0
testerObject3.physicsBody!.contactTestBitMask = 0
testObject.addChild(testerObject3)

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)
}

Add SKShapeNode in another one

I want to draw a square in another square; but I can't position the second one in the right way.
What can I do for positioning based on first square coordinates?
var tileBackground = SKShapeNode(rectOfSize: CGSize(width: screenWidth, height: screenWidth))
tileBackground.name = "tileBackground"
tileBackground.fillColor = SKColor.whiteColor()
tileBackground.position = CGPoint(x: frame.midX, y: frame.midY);
self.addChild(tileBackground)
var tile = SKShapeNode(rectOfSize: CGSize(width: tileSize, height: tileSize))
tile.name = "tile1"
tile.fillColor = SKColor.redColor()
tile.position = CGPointMake(100,100)
tileBackground.addChild(tile)
You should use SKSpriteNode instead. That way you can add it easily and without setting the position manually. Because in an SKSpriteNode, the center is always the center of the node:
var tileBackground = SKSpriteNode(color: UIColor.whiteColor(), size: CGSizeMake(width: screenWidth, height: screenWidth))
tileBackground.name = "tileBackground"
tileBackground.position = CGPoint(x: frame.midX, y: frame.midY);
self.addChild(tileBackground)
var tile = SKSpriteNode(color: UIColor.redColor(), size: CGSize(width: tileSize, height: tileSize))
tile.name = "tile1"
tileBackground.addChild(tile)
A node's position is relative to its parent position.
If you want the tile node to be in the center of its parent then set its position as:
tile.position = CGPoint(x: tileBackground.size.width / 2.0, y: tileBackground.size.height / 2.0)
which will place the tile in center of the tileBackground node.
also note that you do not need to update the tile position to "follow" the tileBackground node. Updating the tileBackground position will automatically keep the tile in its center

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)