How to detect collision without physics - swift

I want to detect when two bodies contact without using didBeginContact() function
I try with CGRectIntersectsRect() without any effect.
class GameScene: SKScene, SKPhysicsContactDelegate {
// Player
var _player = SKNode()
var platform = SKNode()
let heroCategory: UInt32 = 1 << 0
let platformCategory: UInt32 = 1 << 1
override func didMoveToView(view: SKView) {
/* Setup your scene here */
// Setup
self.anchorPoint = CGPointMake(0.5, 0.5)
self.physicsWorld.gravity = CGVectorMake(0.0, -2.0);
self.physicsWorld.contactDelegate = self
// Start populating
_player = creatPlayer()
self.addChild(_player)
platform = creatPlatform(1, atPosition: CGPoint(x: 0, y: -200))
self.addChild(platform)
let platformTwo = creatPlatform(2, atPosition: CGPoint(x: 0, y: 200))
self.addChild(platformTwo)
}
func creatPlatform(type: Int, atPosition: CGPoint) -> PlatformNode {
let node = PlatformNode()
node.platformType = type
node.position = atPosition
let sprite = SKSpriteNode(color: UIColor.redColor(), size: CGSize(width: 200, height: 50))
node.addChild(sprite)
node.physicsBody = SKPhysicsBody(rectangleOfSize: sprite.size)
node.physicsBody?.dynamic = false;
node.physicsBody?.categoryBitMask = platformCategory
node.physicsBody?.contactTestBitMask = heroCategory
node.physicsBody?.collisionBitMask = 0;
return node
}
func creatPlayer() -> SKNode {
let playerNode = SKNode()
let sprite = SKSpriteNode(color: UIColor.whiteColor(), size: CGSize(width: 50, height: 50))
playerNode.addChild(sprite)
playerNode.physicsBody = SKPhysicsBody(rectangleOfSize: sprite.size)
playerNode.physicsBody?.dynamic = false
playerNode.physicsBody?.allowsRotation = false
playerNode.physicsBody?.restitution = 1.0
playerNode.physicsBody?.friction = 0.0
playerNode.physicsBody?.angularDamping = 0.0
playerNode.physicsBody?.linearDamping = 0.0
playerNode.physicsBody?.categoryBitMask = heroCategory
playerNode.physicsBody?.contactTestBitMask = platformCategory
playerNode.physicsBody?.collisionBitMask = 0;
return playerNode
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
_player.physicsBody?.dynamic = true
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
if(CGRectIntersectsRect(platform.frame, _player.frame)){
println("Collision")
}
}
}
Maybe using CGRectIntersectsRect is a wrong approach, but I can be used instead?

The frame property
The frame property is a rectangle in the parent’s coordinate system
that contains the node’s content, ignoring the node’s children.
Also from docs:
The frame is non-empty if the node’s class draws content.
And because SKNode class does not perform any drawing of its own, and your platform is probably subclass of SKNode and player is SKNode the frame property is always (0,0,0,0).
You can access the real size of a frame in few ways:
You can make player and platform as subclasses of SKSpriteNode.
You can leave them as they are and access the child SKSpriteNode inside them.
You can leave as they are and use calcualteAccumulatedFrame() method.
About calcualteAccumulatedFrame() from docs:
A node’s accumulated frame, retrieved by calling the
calculateAccumulatedFrame method, is the largest rectangle that
includes the frame of the node and the frames of all its descendants.

Related

How do I properly add a SKPhysicsBody to a drawn line using SKShapeNode in Spritekit?

I'm creating a game where the user must draw a line to collide with a ball to move it from one location to another. I just can't seem to find a way to put a physics body that collides with another object. The drawn line goes through other objects. I've tried several different SKPhysicBody init's on my shape, and none of them seem to work.
What's the best SKPhysicsBody initializer for a drawn line?
Are my category bit mask correct?
I understand the SkShapeNode can be converted to a SkSpriteNode, but I don't want to do this unless its the only way.
import SpriteKit
import UIKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var lines: [Line] = []
var lastTouch: CGPoint?
var touchLocation: CGPoint!
var linePhysics: CGPoint?
var ballCategory:UInt32 = 0b1
var lineCategory:UInt32 = 0b1 << 1
var goalCategory:UInt32 = 0b1 << 2
var floorCategory:UInt32 = 0b1 << 3
override func didMove(to view: SKView) {
self.physicsWorld.contactDelegate = self
// assigns metal ball that was a color Sprite node, and is now a SKSpriteNode
let metalBall:SKSpriteNode = self.childNode(withName: "ball") as! SKSpriteNode
//assigns physical properties
metalBall.position = CGPoint(x: -150, y: 100)
metalBall.physicsBody? = SKPhysicsBody(circleOfRadius: metalBall.size.width / 2)
metalBall.physicsBody?.affectedByGravity = true
metalBall.physicsBody?.isDynamic = true
metalBall.physicsBody?.categoryBitMask = ballCategory
metalBall.physicsBody?.collisionBitMask = floorCategory | lineCategory
let floor: SKSpriteNode = self.childNode(withName: "floor") as! SKSpriteNode
floor.position = CGPoint (x: 0, y: -76)
floor.physicsBody = SKPhysicsBody(rectangleOf: floor.size)
floor.physicsBody?.affectedByGravity = false
floor.physicsBody?.isDynamic = false
floor.physicsBody?.categoryBitMask = floorCategory
floor.physicsBody?.collisionBitMask = ballCategory
}
/**
* Assigns the first touch location to a variable lastTouch
**/
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let firstTouch = touches.first {
lastTouch = firstTouch.location(in: self)
}
}
/**
* Assigns a path to where the finger touches then adds it to the line array and draws a path using shape nodes
**/
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let firstTouch = touches.first {
touchLocation = firstTouch.location(in: self)
//adds coordinates of lines to the line array
lines.append(Line(start: lastTouch!, end: touchLocation))
lastTouch = touchLocation
}
// path is a changeable variable that assigns a path depending on touch
let path = CGMutablePath()
for line in lines {
path.move(to: CGPoint(x: line.start.x, y: line.start.y))
path.addLine(to: CGPoint(x: line.end.x , y: line.end.y))
}
// colors in the path with ui color black
let shape = SKShapeNode()
shape.path = path
shape.strokeColor = UIColor.black
shape.lineWidth = 2
addChild(shape)
**shape.physicsBody = SKPhysicsBody(edgeChainFrom: shape.path!)**
shape.physicsBody?.affectedByGravity = true
shape.physicsBody?.isDynamic = false
shape.physicsBody?.friction = 1
shape.physicsBody?.restitution = 0.1
shape.physicsBody?.angularDamping = 0.0
shape.physicsBody?.linearDamping = 0
**shape.physicsBody?.categoryBitMask = lineCategory
shape.physicsBody?.collisionBitMask = ballCategory**
}
}

Swift 3 Physicsbody Collisions doesn't work

This is my class for the Player
My Player doesn't collide with the Gamefield they just go through each other.
I dont want them to be on top of each other.
I tried to google the solution but for me it seems that I did mostly all right.
Please Help:
class Player: SKShapeNode {
static public let length: CGFloat = 50
static public let rect = CGRect(x: -length/2, y: -length/2, width: length, height: length)
var life = 100
override init() {
super.init()
self.fillColor = SKColor.blue
self.strokeColor = SKColor.black
self.position = CGPoint(x: 50, y: 50)
self.physicsBody = SKPhysicsBody(edgeLoopFrom: Player.rect)
self.physicsBody?.isDynamic = true
self.physicsBody?.allowsRotation = false
self.physicsBody?.categoryBitMask = PhysicsCategory.Robot
self.physicsBody?.contactTestBitMask = PhysicsCategory.Projectile
self.physicsBody?.collisionBitMask = PhysicsCategory.Gamefield
self.physicsBody?.usesPreciseCollisionDetection = true
}; required init?(coder aDecoder: NSCoder) {fatalError("init(coder:) has not been implemented")}
func moveBy(vect: CGVector) {
self.position.x += vect.dx
self.position.y += vect.dy
//print(vect.dx, vect.dy)
}
}
This is my Gamescene Class
struct PhysicsCategory {
static let None : UInt32 = UInt32.min
static let All : UInt32 = UInt32.max
static let Robot : UInt32 = 0b0001 // 1
static let Gamefield : UInt32 = 0b0010 // 2
static let Monster : UInt32 = 0b0011 // 3
static let Projectile : UInt32 = 0b0100 // 4
}
class GameScene: SKScene, SKPhysicsContactDelegate {
var player = Player(rect: Player.rect)
var controlL: Control
var controlR: Control
var cam = SKCameraNode()
override init(size: CGSize) {
controlL = Control(posX: 0, size: size, direction: 1)
controlR = Control(posX: size.width, size: size, direction: -1)
super.init(size: size)
}; required init?(coder aDecoder: NSCoder) {fatalError("init(coder:) has not been implemented")}
override func didMove(to view: SKView) {
self.backgroundColor = SKColor.white
physicsWorld.gravity = CGVector.zero
physicsWorld.contactDelegate = self
cam.xScale = 1
cam.yScale = 1
self.camera = cam
player.addChild(cam)
let gameFieldRect = CGRect(x: 0, y: 0, width: 1000, height: 600)
let gameField = SKShapeNode(rect: gameFieldRect)
gameField.fillColor = SKColor.clear
gameField.strokeColor = SKColor.black
gameField.position = CGPoint(x: 0, y: 0)
gameField.physicsBody = SKPhysicsBody(edgeLoopFrom: gameFieldRect)
gameField.physicsBody?.isDynamic = true
gameField.physicsBody?.allowsRotation = false
gameField.physicsBody?.categoryBitMask = PhysicsCategory.Gamefield
gameField.physicsBody?.contactTestBitMask = PhysicsCategory.None
gameField.physicsBody?.collisionBitMask = PhysicsCategory.Robot
self.addChild(gameField)
self.addChild(player)
cam.addChild(controlL.add())
cam.addChild(controlR.add())
I hope someone sees the mistake. It took me quite long allready.
You need to change your robot to a different physics body type (rectangleOf)?:
SpriteKit supports two kinds of physics bodies, volume-based bodies and edge-based bodies. When you create a physics body, its kind, size, and shape are determined by the constructor method you call. An edge-based body does not have mass or volume and is unaffected by forces or impulses in the system. Edge-based bodies are used to represent volume-less boundaries or hollow spaces in your physics simulation. In contrast, volume-based bodies are used to represent objects with mass and volume.
Also, are you using impulses or forces to move your robot? Not .move(to:) or .position =? move and position will break your physics world (it will go through it in some scenarios)
Also, it looks like you need to change your category masks to a proper series (for didBegin(contact:))
it should be, 1, 2 , 4, 8, 16, so on... that is how you get unique contact hits.. Right now you could get a hit of "4" from 0+4 or 1+3... thus, not unique collisions.
Your collisionBitMask looks good though.. They should be bumping into each other.

How to make joints not rotate using sprite kit or another way of making dynamic 2d water

I want to creat a dynamic 2D water, i', following this unity tutorials
http://gamedevelopment.tutsplus.com/tutorials/creating-dynamic-2d-water-effects-in-unity--gamedev-14143
http://gamedevelopment.tutsplus.com/tutorials/make-a-splash-with-2d-water-effects--gamedev-236
And also this one
http://blog.prime31.com/water2d-part1/
Here is my code
class GameScene: SKScene, SKPhysicsContactDelegate {
var box: SKSpriteNode!
var nodes:[SKNode] = []
override func didMoveToView(view: SKView) {
/* Setup your scene here */
self.anchorPoint = CGPointMake(0.5, 0.5)
// Set physics body
let borderBody: SKPhysicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame);
borderBody.friction = 0.0;
self.physicsBody = borderBody;
// Set contact delegate
self.physicsWorld.contactDelegate = self;
box = SKSpriteNode(color: UIColor.blackColor(), size: CGSize(width: 200, height: 20))
box.position = CGPointMake(0, 0)
box.physicsBody = SKPhysicsBody(rectangleOfSize: box.size)
box.physicsBody!.dynamic = false
self.addChild(box)
let one = SKSpriteNode(color: UIColor.greenColor(), size: CGSize(width: 20, height: 20))
one.position = CGPointMake(box.position.x - box.frame.size.width/2, box.position.y + box.frame.size.height * 2)
one.physicsBody = SKPhysicsBody(rectangleOfSize: one.size)
one.physicsBody!.allowsRotation = false
self.addChild(one)
nodes.append(one)
self.attachPoint(box, point2: one, box: true)
let two = SKSpriteNode(color: UIColor.greenColor(), size: CGSize(width: 20, height: 20))
two.position = CGPointMake(box.position.x, box.position.y + box.frame.size.height * 2)
two.physicsBody = SKPhysicsBody(rectangleOfSize: two.size)
two.physicsBody!.allowsRotation = false
self.addChild(two)
nodes.append(two)
self.attachPoint(box, point2: two, box: true)
let three = SKSpriteNode(color: UIColor.greenColor(), size: CGSize(width: 20, height: 20))
three.position = CGPointMake(box.position.x + box.frame.size.width/2, box.position.y + box.frame.size.height * 2)
three.physicsBody = SKPhysicsBody(rectangleOfSize: three.size)
three.physicsBody!.allowsRotation = false
self.addChild(three)
nodes.append(three)
self.attachPoint(box, point2: three, box: true)
self.attachPoint(one, point2: two, box: false)
self.attachPoint(two, point2: three, box: false)
}
func attachPoint(point1: SKSpriteNode, point2: SKSpriteNode, box: Bool){
if(box == true){
let newPoint1 = CGPointMake(self.frame.size.width/2 + point2.position.x, self.frame.size.height/2 + point1.position.y)
let newPoint2 = CGPointMake(self.frame.size.width/2 + point2.position.x, self.frame.size.height/2 + point2.position.y)
// create a joint between two bodies
let joint: SKPhysicsJointSpring = SKPhysicsJointSpring.jointWithBodyA(point1.physicsBody, bodyB: point2.physicsBody, anchorA: newPoint1, anchorB: newPoint2)
joint.damping = 2.0
joint.frequency = 9.0;
self.physicsWorld.addJoint(joint)
} else {
let newPoint1 = CGPointMake(self.frame.size.width/2 + point1.position.x, self.frame.size.height/2 + point1.position.y)
let newPoint2 = CGPointMake(self.frame.size.width/2 + point2.position.x, self.frame.size.height/2 + point2.position.y)
// create a joint between two bodies
let joint: SKPhysicsJointSpring = SKPhysicsJointSpring.jointWithBodyA(point1.physicsBody, bodyB: point2.physicsBody, anchorA: newPoint1, anchorB: newPoint2)
joint.damping = 2.0
joint.frequency = 9.0;
self.physicsWorld.addJoint(joint)
}
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
let node = nodes[2]
node.physicsBody?.velocity.dy = 20000
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
Here is the result
This result without changes
After touch, execute code in touchesBegan method
After step 2, the nodes start to rotate and fall bellow the node
If they don't rate, following the the tutorials I will have to make SKShapeNode with the color of the node. But SKShapeNode is expensive, is there another way this effect can be accomplished?
The easiest way is to use image for the top part of the water and make it move back and forth, but it won't be dynamic..
If you have ever play Tiny Wings, the water there is implemented exactly the same way in the tutorials.
I don't know, maybe this can't be made in SpriteKit or I just don't know how

SKLabel won't show up

Im making a flappy bird type game in swift using sprite kit. The game works fine but I'm trying to make a way to score the game so I set up a variable and SKLabel that adds on to itself whenever a pipe is about half way across the screen. However I cannot get the label to show up any help doing this here is my code:
// flappy rainbow sheep
//
// Created by Heather Arnold on 3/3/15.
// Copyright (c) 2015 ian arnold. All rights reserved.
//
import SpriteKit
class GameScene: SKScene {
var bird = SKSpriteNode()
var pipeUpTexture = SKTexture()
var pipeDownTexture = SKTexture()
var PipeMoveAndRemove = SKAction()
let pipeGap = 225.0
var score: Int = 0
var scoreLabel: SKLabelNode = SKLabelNode(fontNamed:"System-Bold")
override func didMoveToView(view: SKView) {
/* Setup your scene here */
score = 0
//Physics
self.physicsWorld.gravity = CGVectorMake(0.0, -10.0);
//Bird
var BirdTexture = SKTexture(imageNamed:"flappysheep")
BirdTexture.filteringMode = SKTextureFilteringMode.Nearest
bird = SKSpriteNode(texture: BirdTexture)
bird.setScale(0.5)
bird.position = CGPoint(x: self.frame.size.width * 0.35, y: self.frame.size.height * 0.6)
scoreLabel.position.x = 50
scoreLabel.position.y = view.bounds.height - 50
scoreLabel.text = "0"
scoreLabel.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Left
scoreLabel.hidden = false
self.addChild(scoreLabel)
bird.physicsBody = SKPhysicsBody(circleOfRadius:bird.size.height/4.0);
bird.physicsBody?.dynamic = true
bird.physicsBody?.allowsRotation = false
self.addChild(bird)
//off screen
//Ground
var groundTexture = SKTexture(imageNamed:"rainbowobstacle")
var sprite = SKSpriteNode(texture: groundTexture)
sprite.setScale(2.0)
sprite.position = CGPointMake(self.size.width/2.0, sprite.size.height/2.0)
self.addChild(sprite)
var ground = SKNode()
ground.position = CGPointMake(0, groundTexture.size().height)
ground.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.frame.size.width, groundTexture.size().height * 2.0))
ground.physicsBody?.dynamic = false
self.addChild(ground)
//Pipes
//create the pipes
pipeUpTexture = SKTexture(imageNamed:"rainbowpipe")
pipeDownTexture = SKTexture(imageNamed:"rainbowpipe")
//move pipes
let distanceToMove = CGFloat(self.frame.size.width + 2.0 * pipeUpTexture.size().width)
let movePipes = SKAction.moveByX(-2500, y: 0.0, duration: NSTimeInterval(0.01 * distanceToMove))
let removePipes = SKAction.removeFromParent()
PipeMoveAndRemove = SKAction.sequence([movePipes, removePipes])
//spwan pipes
let spawn = SKAction.runBlock({() in self.spawnPipes()})
let delay = SKAction.waitForDuration(NSTimeInterval(0.2))
let spawnThenDelay = SKAction.sequence([spawn, delay])
let spawnThenDelayForever = SKAction.repeatActionForever(spawnThenDelay)
self.runAction(spawnThenDelayForever)
let pipeUp = SKSpriteNode(texture:pipeUpTexture)
if (pipeUp.position.x + (pipeUp.size.width / 2) < self.view!.bounds.size.width / 2)
{
score++
}
scoreLabel.hidden = false
}
func spawnPipes(){
let pipePair = SKNode()
pipePair.position = CGPointMake(self.frame.size.width + pipeUpTexture.size().width * 2, 0)
pipePair.zPosition = -10
let height = UInt32(self.frame.size.height / 4)
let y = arc4random() % height + height
let pipeDown = SKSpriteNode(texture:pipeDownTexture)
pipeDown.setScale(2.0)
pipeDown.position = CGPointMake(0.0, CGFloat(y) + pipeDown.size.height + CGFloat(pipeGap))
pipeDown.physicsBody = SKPhysicsBody(rectangleOfSize:pipeDown.size)
pipeDown.physicsBody?.dynamic = false
pipePair.addChild(pipeDown)
let pipeUp = SKSpriteNode(texture:pipeUpTexture)
pipeUp.setScale(2.0)
pipeUp.position = CGPointMake(0.0, CGFloat(y))
pipeUp.physicsBody = SKPhysicsBody(rectangleOfSize: pipeUp.size)
pipeUp.physicsBody?.dynamic = false
pipePair.addChild(pipeUp)
pipePair.runAction(PipeMoveAndRemove)
self.addChild(pipePair)
}
class GameScene: SKScene {
let bird = SKSpriteNode()
var gameOver = false
override init(size: CGSize) {
super.init(size: size)
self.bird.position = CGPoint(x: 0, y: 0)
self.addChild(self.bird)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func endGame(){
// restart the game
let gameScene = GameScene(size: self.size)
self.view!.presentScene(gameScene)
}
override func update(currentTime: NSTimeInterval) {
// our bird doesnt intersect the frame,
// we use gameOver bool so we dont call endGame more than once
if !self.frame.intersects(self.bird.frame) && !self.gameOver{
self.gameOver = true
self.endGame()
}
}
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
bird.physicsBody?.velocity = CGVectorMake(0, 0)
bird.physicsBody?.applyImpulse(CGVectorMake(0, 8))
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
Your label might be covered over by another image. Try setting the SKLabelNode zPosition property to a higher value. Perhaps something like 900.
Try setting the zPosition of the label to one.
scoreLabel.zPosition = 1
This should make the node appear even if another node passes over it.
Here are two other functions that may assist you also:
scoreLabel.color = UIColor.blackColor()//set color to black - you can use any almost color here
scoreLabel.fontSize = 32//changes font size to make label bigger/smaller

Collision Detection In Sprite Kit using Swift

The code below is from a project I am currently working on, I have been trying to teach myself Swift language and Sprite Kit for the past few days and this is my first attempt at a game, it is a Flappy Bird type game. I ran into a problem today when I was trying to write the code for the collision detection. When the bird touches one of the pipes the game is supposed to pause. However when I run the code and the bird touches the pipe, nothing happens, the bird just bounces off of it. I have read many tutorials and watched many videos on this subject to try and resolve my problem and haven't had any luck. I have written all of the collision detection code that I learned off of the last video I watched in the code below. Could anyone please tell me what I am doing wrong. Any advice would be greatly appreciated, thank you.
//
// GameScene.swift
// Bird Flappy Game
//
// Created by Brandon Ballard on 1/4/15.
// Copyright (c) 2015 Brandon Ballard. All rights reserved.
//
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var bird = SKSpriteNode()
var pipeUpTexture = SKTexture()
var pipeDownTexture = SKTexture()
var pipesMoveAndRemove = SKAction()
let pipeGap = 150.0
enum ColliderType:UInt32 {
case BIRD = 1
case PIPE = 2
}
override func didMoveToView(view: SKView) {
/* Setup your scene here */
backgroundColor = SKColor.cyanColor()
//physics
self.physicsWorld.gravity = CGVectorMake(0.0, -15.0);
self.physicsWorld.contactDelegate = self
func didBeginContact(contact: SKPhysicsContactDelegate) {
scene?.view?.paused = true
bird.setScale(12.0)
}
//Bird
var birdTexture = SKTexture(imageNamed:"Bird")
birdTexture.filteringMode = SKTextureFilteringMode.Nearest
bird = SKSpriteNode(texture: birdTexture)
bird.setScale(0.6)
bird.position = CGPoint(x: 375, y: self.frame.size.height * 0.6)
bird.physicsBody = SKPhysicsBody(circleOfRadius: bird.size.height / 2.0)
bird.physicsBody?.dynamic = true
bird.physicsBody?.allowsRotation = true
bird.physicsBody?.affectedByGravity = true
bird.physicsBody!.categoryBitMask = ColliderType.BIRD.rawValue
bird.physicsBody!.contactTestBitMask = ColliderType.PIPE.rawValue
bird.physicsBody!.collisionBitMask = ColliderType.PIPE.rawValue
self.addChild(bird)
//Ground
var groundTexture = SKTexture(imageNamed: "Ground")
var sprite = SKSpriteNode(texture: groundTexture)
sprite.setScale(2.0)
sprite.position = CGPointMake(self.size.width / 2, sprite.size.height / 2.0)
self.addChild(sprite)
var ground = SKNode()
ground.position = CGPointMake(0, groundTexture.size().height + 0)
ground.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.frame.size.width, groundTexture.size().height * 2.0))
ground.physicsBody?.dynamic = false
self.addChild(ground)
//Pipes
//Create the Pipes
pipeUpTexture = SKTexture(imageNamed: "PipeUp")
pipeDownTexture = SKTexture(imageNamed: "PipeDown")
//Movement of Pipes
let distanceToMove = CGFloat(self.frame.size.width + 2.0 * pipeUpTexture.size().width)
let movePipes = SKAction.moveByX(-distanceToMove, y: 0.0, duration: NSTimeInterval(0.01 * distanceToMove))
let removePipes = SKAction.removeFromParent()
pipesMoveAndRemove = SKAction.sequence([movePipes,removePipes])
//Spawn Pipes
let spawn = SKAction.runBlock({() in self.spawnPipes()})
let delay = SKAction.waitForDuration(NSTimeInterval(2.0))
let spawnThenDelay = SKAction.sequence([spawn,delay])
let spawnThenDelayForever = SKAction.repeatActionForever(spawnThenDelay)
self.runAction(spawnThenDelayForever)
}
func spawnPipes() {
let pipePair = SKNode()
pipePair.position = CGPointMake(self.frame.size.width + pipeUpTexture.size().width * 2, 0)
pipePair.zPosition = -10
let height = UInt32(self.frame.size.height / 4)
let y = arc4random() % height + height
var pipeDown = SKSpriteNode(texture: pipeDownTexture)
pipeDown.setScale(2.0)////////
pipeDown.position = CGPointMake(3.0, CGFloat(y) + pipeDown.size.height + CGFloat(pipeGap) )
pipeDown.physicsBody = SKPhysicsBody(rectangleOfSize: pipeDown.size)
pipeDown.physicsBody?.dynamic = false
pipeDown.physicsBody!.affectedByGravity = false
pipeDown.physicsBody!.categoryBitMask = ColliderType.PIPE.rawValue
pipeDown.physicsBody!.contactTestBitMask = ColliderType.BIRD.rawValue
pipeDown.physicsBody!.collisionBitMask = ColliderType.BIRD.rawValue
pipePair.addChild(pipeDown)
var pipeUp = SKSpriteNode(texture: pipeUpTexture)
pipeUp.setScale(2.0)
pipeUp.position = CGPointMake(0.0, CGFloat(y))
pipeUp.physicsBody = SKPhysicsBody(rectangleOfSize: pipeUp.size )
pipeUp.physicsBody?.dynamic = false
pipeUp.physicsBody!.affectedByGravity = false
pipeUp.physicsBody!.categoryBitMask = ColliderType.PIPE.rawValue
pipeUp.physicsBody!.contactTestBitMask = ColliderType.BIRD.rawValue
pipeUp.physicsBody!.collisionBitMask = ColliderType.BIRD.rawValue
pipePair.addChild(pipeUp)
pipePair.runAction(pipesMoveAndRemove)
self.addChild(pipePair)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
bird.physicsBody?.velocity = CGVectorMake( 0, 0 )
bird.physicsBody?.applyImpulse(CGVectorMake(0,25))
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
From what I can see, you only need to DETECT collisions, not actually simulate them. For this, you need to set only the contactTestBitMask of the physicsBodies. You can set the collisionBitMask as 0.
bird.physicsBody!.collisionBitMask = 0
pipe.physicsBody!.collisionBitMask = 0
Also, as hamobi has already said, the didBeginContact method needs to be outside the didMoveToView method with the override keyword. (This question has the exact same problem as yours)
class GameScene: SKScene, SKPhysicsContactDelegate {
// ...
override func didMoveToView(view: SKView) {
self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
// set as delegate:
self.physicsWorld.contactDelegate = self
// ..
}
// should be called now
func didBeginContact(contact: SKPhysicsContact){
scene?.view?.paused = true
bird.setScale(12.0)
}
}
You put your didBeginContact INSIDE of didMoveToView. It's not callable from there. Put it in the body of your class