How do I avoid hard coding values? - ios

In my application, I have items randomly popping up from the bottom of the screen. The way I set my code forced me to use hard coded values for x-position from where the items are popping up. Instead of those x-positions being hard coded, I want to change them to for instance GameScene.size.width / 4, so that the application's game play stays the same for all devices. Here is how I set up my code:
class Items{
var node = SKNode()
var item1 = SKSpriteNode(imageNamed: "CY")
var item2 = SKSpriteNode(imageNamed: "SY")
var item3 = SKSpriteNode(imageNamed: "PY")
var velocity = CGPoint.zero
var positionOffset = CGFloat(0)
var minVelocity = CGFloat(200)
init(pOffset: CGFloat) {
positionOffset = pOffset
node.zPosition = 1
node.addChild(item1)
node.addChild(item2)
node.addChild(item3)
node.hidden = true
}
....
class GameWorld{
var size = CGSize()
var node = SKNode()
var can1 = Items(pOffset: 208) //this is what is deciding the position
var can2 = Items(pOffset: 620)
init() {
node.addChild(can1.node)
node.addChild(can2.node)
}
....
The offset line in GameWorld class is what is deciding the position. What can I change in order to be able to say "GameScene.size.width / 4" for can 1 and similarly the same for can2 and not have an issue? I did try different ways to get it to work, but nothing seems to go my way. When I'm able to say GameScene.size.width / 4, for some reason, the app launches, but none of the gameplay loads up. Any help will be greatly appreciated.
Here is my GameScene Class:
class GameScene: SKScene {
... // added sprites but erased the code for now for space purposes
var touchLocation = CGPoint(x: 0, y: 0)
var nrTouches = 0
var rightTap: Bool = false
var leftTap: Bool = false
var delta: NSTimeInterval = 1/60
static var world = GameWorld()
override init(size: CGSize) {
super.init(size: size)
GameScene.world.size = size
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func didMoveToView(view: SKView) {
backgroundColor = UIColor.whiteColor()
let pos1 = CGPoint(x: size.width / 1.333, y: size.height / 1.1)
addChild(GameScene.world.node)
delta = NSTimeInterval(view.frameInterval) / 60
sprite1.position = pos1
sprite2.position = pos1
sprite3.position = pos1
sprite1.zPosition = 2
sprite2.zPosition = 2
sprite3.zPosition = 2
sprite2.hidden = true
sprite3.hidden = true
addChild(sprite1)
addChild(sprite2)
addChild(sprite3)
}
.....
Edit: added GameScene Class

For this scenario, you cannot declare:
var can1 = Items(pOffset: 208)
var can2 = Items(pOffset: 620)
The way you are doing it now. This is because at compile time, the game has no idea what the screen size is. Instead do not initialize the variable, just declare it like this:
var can1 : Items!
var can2 : Items!
Then this next part is tricky, if you are doing auto layouts, you need to make sure that the view is already created and sized before you present your scene. This does't happen till somewhere around viewDidAppear in the view controller
In your scenes didMoveToView, initialize your variables:
override func didMoveToView(view : SKView)
{
... //super and other code
can1 = Items(pOffset: view.frame.size.width/4)
can2 = Items(pOffset: view.frame.size.width/2)
}

Related

I made a hitbox sprite as a child to my player, in my player Class. how do I access that hitbox sprite in gamescene's didBegin method?

The purpose of this "hitbox" is so the player will only be able to jump while walking on top of ground/platforms.The hitbox is a little less wide then the player and is on the players feet. Here's my player class:
class Player: SKSpriteNode {
let maxPlayerSpeed:CGFloat = 300
static var isPlayerOnGround = false
init() {
//players texture
let texture = SKTexture(imageNamed: "playerMove1")
super.init(texture: texture, color: SKColor.clear, size: texture.size())
//hitbox that sits underneath the player and follows him
let jumpHitBox = SKSpriteNode(color: .red, size: CGSize(width: texture.size().width - (texture.size().width / 8), height: texture.size().height / 5))
jumpHitBox.position.y = (-texture.size().height) + (texture.size().height / 2)
jumpHitBox.alpha = 0.5
jumpHitBox.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: jumpHitBox.size.width,
height: jumpHitBox.size.height))
jumpHitBox.zPosition = 3
jumpHitBox.physicsBody?.pinned = true
jumpHitBox.physicsBody?.allowsRotation = false
jumpHitBox.physicsBody?.categoryBitMask = CollisionTypes.playerJump.rawValue
jumpHitBox.physicsBody?.collisionBitMask = 0
jumpHitBox.physicsBody?.contactTestBitMask = CollisionTypes.ground.rawValue
addChild(jumpHitBox)
physicsBody = SKPhysicsBody(rectangleOf: size)
physicsBody?.categoryBitMask = CollisionTypes.player.rawValue
physicsBody?.contactTestBitMask = CollisionTypes.star.rawValue | CollisionTypes.saw.rawValue | CollisionTypes.finish.rawValue
physicsBody?.collisionBitMask = CollisionTypes.ground.rawValue
physicsBody?.affectedByGravity = true
physicsBody?.restitution = 0.2
physicsBody?.isDynamic = true
physicsBody?.allowsRotation = false
setScale(0.6)
zPosition = 5
physicsBody?.linearDamping = 0.0 }
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder) //error here
}
I want to use the jumpHitBox in this method as an additional contact.bodyA/B node in GameScene.swift:
func didBegin(_ contact: SKPhysicsContact) {
if contact.bodyA.node == player {
playerCollided(with: contact.bodyB.node!)
} else if contact.bodyB.node == player {
playerCollided(with: contact.bodyA.node!)
}
}
I don't know how to reference the the jumpHitBox child node from my player class in the didBegin in GameScene.swift.
Any advice is greatly appreciated.
EDIT: I'm getting an error at the
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder) //error here
}
I dont put anything in here in my player class but since moving the jumpHitBox sprite to a global declaration I get an error at the super.init(coder: aDecoder) line in the required init saying: Property 'self.jumpHitBox' not initialized at super.init call
Although I would try the much simpler velocity.dy approach as mentioned in comments, your problem is that your hitbox is declared inside the scope of an initializer, so you can only access it there. If you give the hitbox a higher scope, such as a class property, then you can access it most anywhere:
class Player: SKSpriteNode {
let maxPlayerSpeed:CGFloat = 300
// This is probably going to cause you bugs later btw.. it should probably be
// just a regular property:
static var isPlayerOnGround = false
// Now you can just call playerInstance.jumpHitBox :
private(set) var jumpHitBox = SKSpriteNode()
init() {
//players texture
let texture = SKTexture(imageNamed: "playerMove1")
super.init(texture: texture, color: SKColor.clear, size: texture.size())
jumpHitBox = SKSpriteNode(color: .red, size: CGSize(width: texture.size().width - (texture.size().width / 8), height: texture.size().height / 5))
//hitbox that sits underneath the player and follows him
}
}
UPDATE:
class Player: SKSpriteNode {
let maxPlayerSpeed:CGFloat = 300
// This is probably going to cause you bugs later btw.. it should probably be
// just a regular property:
static var isPlayerOnGround = false
// Now you can just call playerInstance.jumpHitBox :
var jumpHitBox = SKSpriteNode()
private func makeHitBox() -> SKSpriteNode {
let texture = SKTexture(imageNamed: "playerMove1")
//hitbox that sits underneath the player and follows him
let localJumpHitBox = SKSpriteNode(color: .red, size: CGSize(width: texture.size().width - (texture.size().width / 8), height: texture.size().height / 5))
localJumpHitBox.position.y = (-texture.size().height) + (texture.size().height / 2)
localJumpHitBox.alpha = 0.5
localJumpHitBox.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: localJumpHitBox.size.width,
height: localJumpHitBox.size.height))
localJumpHitBox.zPosition = 3
localJumpHitBox.physicsBody?.pinned = true
localJumpHitBox.physicsBody?.allowsRotation = false
localJumpHitBox.physicsBody?.categoryBitMask = CollisionTypes.playerJump.rawValue
localJumpHitBox.physicsBody?.collisionBitMask = 0
localJumpHitBox.physicsBody?.contactTestBitMask = CollisionTypes.ground.rawValue
return localJumpHitBox
}
init() {
//players texture
let texture = SKTexture(imageNamed: "playerMove1")
super.init(texture: texture, color: SKColor.clear, size: texture.size())
physicsBody = SKPhysicsBody(rectangleOf: size)
physicsBody?.categoryBitMask = CollisionTypes.player.rawValue
physicsBody?.contactTestBitMask = CollisionTypes.star.rawValue | CollisionTypes.saw.rawValue | CollisionTypes.finish.rawValue
physicsBody?.collisionBitMask = CollisionTypes.ground.rawValue
physicsBody?.affectedByGravity = true
physicsBody?.restitution = 0.2
physicsBody?.isDynamic = true
physicsBody?.allowsRotation = false
setScale(0.6)
zPosition = 5
physicsBody?.linearDamping = 0.0
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder) //error here
jumpHitBox = makeHitBox()
addChild(jumpHitBox)
}
}
One way to reference jumpHitBox from outside its class is by making it a property of the Player class as in let jumpHitBox: SKSpriteNode, in the same way as you have declared maxPlayerSpeed to be a property of the Player class.
If you make this change, then remember to remove the let in this line let jumpHitBox = SKSpriteNode(color: .red .... since you now just need to assign a value to it, instead of declaring it. You should also now move the call to super.init to be after this line. Otherwise the compiler will complain, i.e. all properties of a class must be assigned a value before calling super.init.
The jumpHitBox should be now be accessible in didBegin by using player.hitBox
Hope this helps!
Here is a secondary answer showing a different approach to your problem. Note, the player only jumps when on the ground. This uses a "delayed frame" or "frame skip" or however you want to put it, because the jump command (pb.applyImpulse) is only called inside of didSimulatePhysics which means the character won't actually go any higher until the next frame.
// NOTE: This is a very simple example. The player bounces a bit on landing,
// which is essentially "landing lag" before you can jump again. In other words,
// the less the player bounces when contact the ground, the faster the player
// can jump again. There are ways to make this bouncing effect minimal / 0, but would
// require more work to implement, and I don't have any brilliantly simple ideas at the moment.
class GameScene : SKScene {
var player = SKSpriteNode(color: .blue, size: CGSize(width: 50, height: 50))
var initialY = CGFloat(0)
var flag_wantsToJump = false
override func didMove(to view: SKView) {
self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
let pb = SKPhysicsBody(rectangleOf: player.size)
pb.restitution = 0
player.physicsBody = pb
addChild(player)
}
override func mouseDown(with event: NSEvent) {
// Tells game that we want to jump next frame:
flag_wantsToJump = true
}
override func update(_ currentTime: TimeInterval) {
// Give us new, initial frame data to compare against whatever our position.y will be
// later in the frame:
let curY = player.position.y
initialY = curY
}
override func didSimulatePhysics() {
// Determine whether or not we want to jump next frame:
guard flag_wantsToJump else { return }
// Determine whether or not we are allowed to jump:
let curY = player.position.y
print(curY, initialY)
if curY == initialY {
// Even though we are calling .applyImpulse this frame, it won't be processed
// until next frame--because we are calling this from inside `didSimulatePhysics`!
player.physicsBody!.applyImpulse(CGVector(dx: 0, dy: 75))
}
}
override func didFinishUpdate() {
// Clear our flags for new mouse / touch input for next frame:
flag_wantsToJump = false
}
}

Prevent two SKSpriteNodes from overlapping

I want to reproduce Super-Mario for iOS using Swift and SpriteKit. I use SKPhysics-bodies to simulate collisions between the player and the environment. The player and all objects have their own SKPhysicsBody (rectangle of their size). But when the player jumps against a brick (from top left or top right) like this, the player stucks in the air.
My assumption is that when the two SKSpriteNodes collide, they overlap a tiny bit. And the SKPhysics-Engine thinks that the player is on top of the middle brick because the player is a tiny bit inside the brick above and falls down on the middle brick.
So my question is: How can i prevent SKSPriteNodes from overlapping? Or how can i fix this?
P.S. If you need more information to answer, please tell me!
EDIT: Some Code of the Brick Class:
import SpriteKit
class Brick: SKSpriteNode {
let imgBrick = SKTexture(imageNamed: "Brick")
init(let xCoor: Float, let yCoor: Float) {
// position is a global variable wich is 1334/3840
super.init(texture: imgBrick, color: UIColor.clearColor(), size: CGSize(width: 80*proportion, height: 80*proportion))
position = CGPoint(x:Int(xCoor*667)+Int(40*proportion), y:Int(375-(yCoor*375))-Int(40*proportion))
name = "Brick"
physicsBody = SKPhysicsBody(rectangleOfSize: self.size)
physicsBody?.affectedByGravity = false
physicsBody?.dynamic = false
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
and my Player Class
import SpriteKit
class Mario: SKSpriteNode {
let atlas = SKTextureAtlas(named: "Mario")
var imgMario = [SKTexture]()
var action = SKAction()
init(let xCoor: Float, let yCoor: Float) {
for(var i = 1; i < 24; i++) {
imgMario.append(atlas.textureNamed("X\(i)"))
}
super.init(texture: imgMario[0], color: UIColor.clearColor(), size: CGSize(width: 120*proportion, height: 160*proportion))
position = CGPoint(x:Int(xCoor)+Int(60*proportion), y:Int(yCoor)-Int(90*proportion))
name = "Mario"
physicsBody = SKPhysicsBody(rectangleOfSize: self.size)
physicsBody?.allowsRotation = false
action = SKAction.repeatActionForever(SKAction.animateWithTextures(imgMario, timePerFrame: 0.03, resize: false, restore: true))
runAction(action, withKey: "walking")
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
and SOME PART of my Level Class
class Level: SKScene, SKPhysicsContactDelegate {
var motionManager = CMMotionManager()
var mario = Mario(xCoor: 100, yCoor: 90)
var world = SKSpriteNode()
let MarioCategory: UInt32 = 0x1 << 0
let BrickCategory: UInt32 = 0x1 << 1
/*
Some more code...
*/
func setUpPhysics() {
physicsWorld.contactDelegate = self
mario.physicsBody!.categoryBitMask = marioCategory
mario.physicsBody?.collisionBitMask = brickCategory
mario.physicsBody?.contactTestBitMask = brickCategory
for(var i = 0; i < world.children.count; i++) {
if(world.children[i].name == "Brick") {
world.children[i].physicsBody?.categoryBitMask = brickCategory
world.children[i].physicsBody?.collisionBitMask = marioCategory
world.children[i].physicsBody?.contactTestBitMask = marioCategory
world.children[i].physicsBody?.friction = 0
}
}
}
}
Try setting UsePreciseCollisionDetection to true on your physicsbody.
mario.physicsBody?.usesPreciseCollisionDetection = true
https://developer.apple.com/reference/spritekit/skphysicsbody has some examples.
By setting this property to true could cause it to detect collisions more accurately so only when you mean to. I'd also rethink giving each block its own physics body. You only really care about the edge of a group of blocks rather than the edges of each individual block.
Another suggestion is that you can create a physics body based on a texture. So if your SKSpriteNode has a complex texture with transparent bits you can create another texture that is just a simple black block or similar this will help the engine detect more accurate collisions.

Contact of Nodes with Subclass

im creating a class to add my Meteors to the scene:
import SpriteKit
class Meteor: SKShapeNode {
var meteorNode : SKShapeNode?
var size : CGSize!
//Acoes
var acaoApagar = SKAction.removeFromParent()
var acaoAndar : SKAction!
//Numero Randomico
var numRandom : Int = 0
var textoStringMeteor : String!
//Colisoes
let CollisionShoot : UInt32 = 0x1 << 0
let CollisionHouse : UInt32 = 0x1 << 1
let CollisionMeteor : UInt32 = 0x1 << 2
init(size : CGSize, pontoMeteor: CGPoint, textoMeteor: String)
{
super.init()
//super.init(ellipseOfSize: <#CGSize#>)
self.size = size
self.textoStringMeteor = textoMeteor
self.acaoAndar = SKAction.moveTo(pontoMeteor, duration: 10)
criarMeteoro()
setarTexto(self.textoStringMeteor)
}
func setarTexto(numeroLabel : String) {
let numNode = SKLabelNode(fontNamed:"Chalkduster")
numNode.text = numeroLabel;
numNode.fontSize = 20;
numNode.position = CGPoint(x: 0, y: -10);
numNode.name = "textoNode"
meteorNode?.addChild(numNode)
}
func criarMeteoro() {
var randomX = CGFloat(Int(arc4random()) % Int(size.width))
//Meteor Node
meteorNode = SKShapeNode(circleOfRadius: CGFloat(20))
meteorNode!.physicsBody = SKPhysicsBody(circleOfRadius: 20)
meteorNode!.physicsBody!.dynamic = true
meteorNode!.fillColor = UIColor.blueColor()
meteorNode!.physicsBody!.categoryBitMask = CollisionMeteor
meteorNode!.physicsBody!.contactTestBitMask = CollisionShoot | CollisionHouse
meteorNode!.position = CGPoint(x: randomX, y: size.height + 900)
meteorNode!.name = "meteorNode"
self.addChild(meteorNode!)
meteorNode!.runAction(SKAction.sequence([acaoAndar, acaoApagar]))
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Here im calling the class Meteor and passing all parameters:
var meteor = Meteor(size: CGSize(width: size.width, height: size.height), pontoMeteor: ponto, textoMeteor: "30")
foreground.addChild(meteor)
And for the last i have my contact to see if there was contact between the nodes:
func didBeginContact(contact: SKPhysicsContact) {
var bodyA = contact.bodyA!.node!
var bodyB = contact.bodyB!.node!
if bodyA.name == "tiroCanhao" && bodyB.name == "meteorNode"
{
bodyB.removeAllActions()
bodyB.removeFromParent()
bodyA.removeFromParent()
self.pointsPlayer++
self.qtdtiros += 2
}
else if bodyA.name == "meteorNode" && bodyB.name == "tiroCanhao"
{
bodyA.removeAllActions()
bodyA.removeFromParent()
bodyB.removeFromParent()
self.pointsPlayer++
self.qtdtiros += 2
}
}
Now my problem is the follow:
After the contact i want to call the setarTexto method on the Meteor class of the object and change the text but that isnt working. I get this error:
Could not cast value of type 'SKShapeNode' (0x10bb5ea88) to
'MathDefense.Meteor' (0x10af6b7b0).
What im doing is this (on the if statement on contact):
let text = bodyB as! Meteor
text.setarTexto("20")
I even tried
text.textoStringMeteor = "20"
But none of those worked. I already done some research but didn't find any person with my problem or trying to do something similar.
Any solution?
Thanks.
I found the solution, to fix my error i made the following:
Remove the SKShapenode since the class is already a SKShapenode (that was the error).
Then when creating my node i made everthing with self instead of putting in the Meteornode. That fixed all.
Example:
Right: self.position = CGPoint(x: randomX, y: size.height + 900)
Wrong: meteorNode!.position = CGPoint(x: randomX, y: size.height + 900)
To pass texture if you are using a SKSpritenode just put it on your superinit.

Create an array of SKShapeNodes

I'm new to Swift development and I'm trying to create a simple racing game. The road in the game has lane markers that animate from the top of the screen to the bottom then loop back up to the top. I am using SKShapeNodes for the lane line markers.
I have been able to get one lane marker to work and now I just need to create an array(I think?) of lane markers so that I can have 2 columns of lanes and enough to give the game the illusion of being a real road.
I'm able to create the array but I get a run-time error when I try to add a SKShapeNode to it. The error I get is:
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP,subcode=0x0)
fatal error: Cannot index empty buffer
Here is the relevant source code:
class PlayScene: SKScene {
let road = SKSpriteNode(imageNamed: "road8")
let car = SKSpriteNode(imageNamed: "car")
let laneLineNode = SKShapeNode()
var laneLineNodeArray = [[SKShapeNode]]()
var groundSpeed = 25
}
override func didMoveToView(view: SKView) {
//draw a lane line
var path = CGPathCreateMutable();
var laneLineWidth = self.size.width / 85
var laneLineHeight = self.size.height / 11
var laneLine = CGRect(x: ((self.frame.size.width / 5) * 2), y:
(self.frame.size.height + laneLineHeight),
width: laneLineWidth, height: laneLineHeight)
laneLineNode.lineWidth = 0
laneLineNode.path = CGPathCreateWithRect(laneLine, nil)
laneLineNode.fillColor = SKColor.yellowColor()
laneLineNode.zPosition = 2
//THIS IS THE LINE I GET THE ERROR ON
laneLineNodeArray[0][0] = laneLineNode
self.addChild(self.road)
self.addChild(self.laneLineNode)
self.addChild(self.car)
}
override func update(currentTime: CFTimeInterval) {
//move the lane lines
scrollLaneLines(self.scene!)
}
}
Thanks for any help you can give me.
First of all... You are closing your class too soon with this code:
var groundSpeed = 25
} // <--
Second... Your are not initializing your array before using it. In my test, I got the error because of that.
You should use this syntax to initialize your Array or use append as #Arnab suggest.
let laneLineNode = SKShapeNode()
var laneLineNodeArray = [[laneLineNode]]
You have created an empty array so far. Use "append" to add data to the array before you access the elements by index.
Thank you! I was able to get it to work with this in Class PlayScene:
var laneLineNodeArray:[[SKShapeNode]] = []
and this in func didMoveToView:
//draw a lane line
var path = CGPathCreateMutable();
var laneLineWidth = self.size.width / 85
var laneLineHeight = self.size.height / 11
var laneLine = CGRect(x: 0, y: (self.frame.size.height + laneLineHeight),
width: laneLineWidth, height: laneLineHeight)
var laneLineRowNumber: Int
var laneLineY: CGFloat
for r in 0...6 {
var laneLineRow:[LaneLine] = []
laneLineRowNumber = r
for c in 0...1 {
let laneLineNode = LaneLine()
laneLineNode.lineWidth = 0
laneLineNode.path = CGPathCreateWithRect(laneLine, nil)
laneLineNode.fillColor = SKColor.yellowColor()
laneLineNode.zPosition = 2
//lanelineY determines the Y placement of the lane.
laneLineY = self.frame.size.height - (CGFloat((laneLineHeight) * 2)
* CGFloat(r))
if c == 0 {
laneLineNode.position = CGPointMake(laneWidth * 2, laneLineY)
}
else if c == 1 {
laneLineNode.position = CGPointMake(laneWidth * 3, laneLineY)
}
self.addChild(laneLineNode)
laneLineRow.append(laneLineNode)
}
laneLineNodeArray.append(laneLineRow)
}

didBeginContact not being invoked

I have 2 SKSpriteNodes whose contact needs to be detected. I've tried various methods and looked up a lot of stuff but can't seem to get an answer. Below is my code. controlCircle is a class level variable because it needs to be used in other methods. The objects are generated fine.
class GameScene: SKScene, SKPhysicsContactDelegate {
var controlCircle = SKSpriteNode()
var mainCategory : UInt32 = 1 << 0
var dropCategory: UInt32 = 1 << 1
override func didMoveToView(view: SKView) {
self.physicsWorld.contactDelegate = self
self.physicsWorld.gravity = CGVectorMake(0,0)
//CREATING FIRST OBJECT AND ADDING PHYSICS BODY
var mainRadius = 20.0;
var controlCircle = SKSpriteNode(color: UIColor.clearColor(), size:CGSizeMake(mainRadius * 2, mainRadius * 2))
var circleBody = SKPhysicsBody(circleOfRadius: mainRadius)
circleBody.dynamic = false
circleBody.usesPreciseCollisionDetection = true
controlCircle.physicsBody = circleBody
var bodyPath = CGPathCreateWithEllipseInRect(CGRectMake((controlCircle.size.width/2), controlCircle.size.height/2, controlCircle.size.width, controlCircle.size.width),
nil)
var circleShape = SKShapeNode()
circleShape.fillColor = UIColor.brownColor()
circleShape.lineWidth = 0
circleShape.path = bodyPath
controlCircle.addChild(circleShape)
controlCircle.position = CGPointMake(self.frame.width/2, self.frame.height/2)
self.addChild(controlCircle)
controlCircle.physicsBody.categoryBitMask = mainCategory
controlCircle.physicsBody.contactTestBitMask = dropCategory
//CREATING SECOND OBJECT AND ADDING PHYSICS BODY
var radius = 10.0;
var drop = SKSpriteNode(color: UIColor.clearColor(), size:CGSizeMake(radius * 2, radius * 2))
var dropBody = SKPhysicsBody(circleOfRadius: radius)
dropBody.dynamic = false
dropBody.usesPreciseCollisionDetection = true
drop.physicsBody = dropBody
var dropPath = CGPathCreateWithEllipseInRect(CGRectMake((drop.size.width/2), drop.size.height/2, drop.size.width, drop.size.width),
nil)
var dropShape = SKShapeNode()
dropShape.fillColor = UIColor.blackColor()
dropShape.lineWidth = 0
drop.name = "dropMask"
dropShape.path = dropPath
drop.addChild(dropShape)
drop.position = CGPointMake(CGFloat(xValue), self.frame.height-5)
self.addChild(drop)
drop.physicsBody.categoryBitMask = dropCategory
drop.physicsBody.contactTestBitMask = mainCategory
}
func didBeginContact(contact: SKPhysicsContact) -> Void{
NSLog("Hello")
}
}
Good news everyone,
SKPhysicsBody documentation:
The dynamic property controls whether a volume-based body is affected by gravity, friction, collisions with other objects, and forces or impulses you directly apply to the object.
So here is an idea to accomplish stationary objects when not dragging, yet receive collision events. On touchesBegan on a SKSpriteNode, set its physicsBody.dynamic = true, on touchUp physicsBody.dynamic = false
Or, you could just remove gravity from your system and have all nodes with physicsBody.dynamic = true

Resources