didBeginContact for three sprites works for 2 sprites, but not for the third one - Swift2 - ios

I have a bird, multiple desks and a star. When the bird collides with one of the desks, the didBeginContact method works fine, but when it collides with the star, nothing happens. I will copy the code where I added some print statements so it is easier to see what is happening and then I will paste the print statements that it prints out.
Bird (just the initialization of the physicsBody part):
class Bird: SKSpriteNode {
var sc: SKScene!
init(sc: SKScene) {
let texture = SKTexture(imageNamed: "hero")
let size = texture.size()
self.sc = sc
super.init(texture: texture, color: UIColor.clearColor(), size: CGSizeMake(size.width/2, size.height/2))
self.zPosition = Layer.Bird.rawValue
self.name = "bird"
self.physicsBody = SKPhysicsBody(circleOfRadius: self.size.width/2)
self.physicsBody?.categoryBitMask = PhysicsCategory.Bird
self.physicsBody?.collisionBitMask = PhysicsCategory.Desk
self.physicsBody?.contactTestBitMask = PhysicsCategory.Desk | PhysicsCategory.StarSpecial | PhysicsCategory.Star
self.physicsBody?.allowsRotation = true
self.physicsBody?.restitution = 0
self.physicsBody?.usesPreciseCollisionDetection = true
}
// other methods and the required init
}
The star class is constructed the same way so I will just copy physicsBody related code:
self.physicsBody = SKPhysicsBody(circleOfRadius: self.size.width/2, center: self.position)
self.physicsBody?.affectedByGravity = false
self.physicsBody?.pinned = true
self.physicsBody?.categoryBitMask = PhysicsCategory.StarSpecial
self.physicsBody?.collisionBitMask = PhysicsCategory.None
self.physicsBody?.contactTestBitMask = PhysicsCategory.Bird
self.physicsBody?.usesPreciseCollisionDetection = true
self.physicsBody?.allowsRotation = false
self.physicsBody?.restitution = 0
self.physicsBody?.usesPreciseCollisionDetection = true
And the didBeginContact method in GameScene:
func didBeginContact(contact: SKPhysicsContact) {
print("something has collided")
if contact.bodyA.categoryBitMask == PhysicsCategory.Bird && contact.bodyB.categoryBitMask == PhysicsCategory.Desk {
birdSprite.BirdDidCollideWithDesk(contact.bodyA.node as! Bird, desk: contact.bodyB.node as! Desk, scoreClass: scoreClass, scoreLabel: scoreLabel)
print("bird and desk have collided")
} else if contact.bodyA.categoryBitMask == PhysicsCategory.Desk && contact.bodyB.categoryBitMask == PhysicsCategory.Bird {
print("desk and bird have collided")
birdSprite.BirdDidCollideWithDesk(contact.bodyB.node as! Bird, desk: contact.bodyA.node as! Desk, scoreClass: scoreClass, scoreLabel: scoreLabel)
}
if contact.bodyA.categoryBitMask == PhysicsCategory.Bird && contact.bodyB.categoryBitMask == PhysicsCategory.StarSpecial {
print("collided into star1")
starSpecial.removeStar(contact.bodyB.node as! Star)
} else if contact.bodyA.categoryBitMask == PhysicsCategory.StarSpecial && contact.bodyB.categoryBitMask == PhysicsCategory.Bird {
print("collided into star2")
starSpecial.removeStar(contact.bodyB.node as! Star)
}
}
If I run it, I get the following messages:
If the bird collides with a desk: "something has collided", "desk and bird have collided"
If the bird collides with the star: "something has collided"
Neither of second two conditions is met, so the message "collided into star1" or "collided into star2" is not printed out.
Any idea what could be causing this?

Related

Sprite Kit Contact Detection

Basically I have the ground, the player (raymond), and coins.
When the player touches the ground nothing should happen, game continues as normal. When the player comes in contact with the coin, I want it to print to console "coin contact with player".
enum ColliderType: UInt32 {
case Raymond = 1
case Object = 2
case Coin = 3
}
Raymonds physics
raymond.physicsBody = SKPhysicsBody(circleOfRadius: raymondTexture.size().height/2)
raymond.physicsBody!.dynamic = true
raymond.physicsBody!.categoryBitMask = ColliderType.Raymond.rawValue
raymond.physicsBody?.contactTestBitMask = ColliderType.Object.rawValue
raymond.physicsBody?.collisionBitMask = ColliderType.Object.rawValue
Coins Physics
coin.physicsBody = SKPhysicsBody(circleOfRadius: raymondTexture.size().height/2)
coin.physicsBody!.dynamic = true
coin.physicsBody!.categoryBitMask = ColliderType.Coin.rawValue
coin.physicsBody?.contactTestBitMask = ColliderType.Raymond.rawValue
coin.physicsBody?.collisionBitMask = ColliderType.Object.rawValue
Ground Physics if you need
ground.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.frame.size.width, 1))
ground.physicsBody!.dynamic = false
ground.physicsBody!.categoryBitMask = ColliderType.Object.rawValue
ground.physicsBody?.contactTestBitMask = ColliderType.Object.rawValue
ground.physicsBody?.collisionBitMask = ColliderType.Object.rawValue
Heres the contact function I have, I know its wrong and I need help with how to detect the coin and raymond touching.
func didBeginContact(contact: SKPhysicsContact) {
print("coin contact with player")
}
Thanks in advance.
There really is several ways of checking this, Here are 2 of the most basics ways to get you started. The first checks name for contact, and the second checks the CategoryBitMask. It is worth noting that if your PhysicsBodies bitmasks are not set properly contact may never be reported between 2 objects.
Edit Make sure the Scene conforms to SKPhysicsContactDelegate
class GameScene: SKScene, SKPhysicsContactDelegate
...
func didBegin(_ contact: SKPhysicsContact) {
let contactAName = contact.bodyA.node?.name
let contactBName = contact.bodyB.node?.name
if (contactAName == "raymond") || (contactBName == "raymond") {
if (contactAName == "coin") || (contactBName == "coin") {
print("coin contact with player")
return
}
}
//or
if contact.bodyA.categoryBitMask == ColliderType.Coin || contact.bodyB.categoryBitMask == ColliderType.Coin {
if contact.bodyA.categoryBitMask == ColliderType.Raymond || contact.bodyB.categoryBitMask == ColliderType.Raymond {
print("coin contact with player")
return
}
}
}

Collide type source error - spritekit swift game

So I have adjusted my games ball type from a shape to an image which forced me to redo the physics of my game. I am new to swift and have struggled with fixing my collisions in my swift game.
class GameScene: SKScene, GameDelegate, SKPhysicsContactDelegate {
var ball: Ball!
let ballSpeedX = CGFloat(500)
//ball = Ball(imageNamed:"colorBall.png")
enum CollisionTypes: UInt32 {
case Floor = 1
case Ball = 2
}
// board
let boards = Boards.make(CollideType.BoardStart.rawValue)
var lastBoard: SKNode?
var boardSpeedY: CGFloat { get { return CGFloat(160) * accelerate }}
let boardDistanceY = CGFloat(300)
let boardYDistanceHide = CGFloat(30)
override func didMoveToView(view: SKView) {
self.physicsWorld.gravity = CGVectorMake(0, 0)
self.physicsWorld.contactDelegate = self
let flooeBody = SKPhysicsBody.init(edgeLoopFromRect: self.frame)
self.physicsBody = floorBody
self.physicsBody!.affectedByGravity = false
self.physicsBody!.usesPreciseCollisionDetection = true
self.physicsBody!.dynamic = true
self.physicsBody!.mass = 0
self.physicsBody!.friction = 0
self.physicsBody!.linearDamping = 0
self.physicsBody!.angularDamping = 0
self.physicsBody!.restitution = 1
self.physicsBody!.categoryBitMask = CollisionTypes.Floor.rawValue
self.physicsBody!.contactTestBitMask = CollisionTypes.Ball.rawValue
// Prepare the ball - physics engine.
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.frame.width/2)
ball.physicsBody!.affectedByGravity = true
ball.physicsBody!.restitution = 0.8
ball.physicsBody!.linearDamping = 0
ball.physicsBody!.friction = 0.3
ball.physicsBody!.dynamic = true
ball.physicsBody!.mass = 0.5
ball.physicsBody!.allowsRotation = true
ball.physicsBody!.categoryBitMask = CollisionTypes.Ball.rawValue
ball.physicsBody!.contactTestBitMask = CollisionTypes.Floor.rawValue
ball.physicsBody!.collisionBitMask = CollisionTypes.Floor.rawValue
ball.hidden = false
self.addChild(ball)
// scene
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsBody!.categoryBitMask = CollideType.Scene.toMask()
self.physicsBody!.dynamic = false
self.physicsBody!.friction = 0
// ceil
let ceil = SKShapeNode(rectOfSize: CGSize(width: self.frame.width, height: 2))
ceil.position.x = CGRectGetMidX(self.frame)
ceil.position.y = self.frame.height - CGRectGetMidY(ceil.frame)
ceil.physicsBody = SKPhysicsBody(rectangleOfSize: ceil.frame.size)
ceil.physicsBody!.categoryBitMask = CollideType.Ceil.toMask()
ceil.physicsBody!.dynamic = false
ceil.alpha = 0
self.addChild(ceil)
// floor
let floor = SKShapeNode(rectOfSize: CGSize(width: self.frame.width, height: 2))
floor.position.x = CGRectGetMidX(self.frame)
floor.position.y = CGRectGetMidY(floor.frame)
floor.physicsBody = SKPhysicsBody(rectangleOfSize: floor.frame.size)
//floor.physicsBody!.categoryBitMask = CollideType.Floor.toMask() two
floor.physicsBody!.dynamic = false
floor.alpha = 0
self.addChild(floor)
}
That is the scene and physics I attempted to set up and was directed with. Below is the collide errors which cause the app to crash upon touch.
func didBeginContact(contact: SKPhysicsContact) {
let bitMaskAAndB = contact.bodyA.categoryBitMask == CollisionTypes.Floor.rawValue && contact.bodyB.categoryBitMask == CollisionTypes.Ball.rawValue
let ballAndBoardMask = CollideType.Ball.toMask() | boards.usedCollideMasks
// ball and board error: CANNOT CONVERT VALUE OF TYPE BOOL TO EXPCTD ARG TYPE UIINT32
if bitMaskAAndB | ballAndBoardMask == ballAndBoardMask {
let boardNode: SKNode! = contact.bodyA.categoryBitMask == CollideType.Ball.toMask() ? contact.bodyB.node : contact.bodyA.node
let board = boardNode.bind as! BoardDelegate
board.didBeginContact(boardNode, ball: ball, contact: contact, game: self)
}
// ball and ceil => ERROR
else if bitMaskAAndB == CollideType.toMask([.Ball, .Ceil]) {
stopGame()
}
// ball and floor => stop game
else if bitMaskAAndB == CollideType.toMask([.Ball, .Floor]) {
stopGame()
}
}
func didEndContact(contact: SKPhysicsContact) {
let ballAndBoardMask = CollideType.Ball.toMask() | boards.usedCollideMasks
// ball and board, handle it by board delegate
if contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask | ballAndBoardMask == ballAndBoardMask {
let boardNode: SKNode! = contact.bodyA.categoryBitMask == CollideType.Ball.toMask() ? contact.bodyB.node : contact.bodyA.node
let board = boardNode.bind as! BoardDelegate
board.didEndContact(boardNode, ball: ball, contact: contact, game: self)
}
}
CollideType definition as below:
enum CollideType: Int {
case Scene = 0
case Ceil = 1
case Floor = 2
case Ball = 3
case BoardStart = 4
func toMask()-> UInt32 {
return UInt32(1 << self.rawValue)
}
static func toMask(masks: [CollideType])-> UInt32 {
var toMask = UInt32(0)
for type in masks {
toMask |= type.toMask()
}
return toMask
}
So the issue now is that you have two definition for your masks:
Remove this one:
enum CollisionTypes: UInt32 {
case Floor = 1
case Ball = 2
}
Use only this one:
enum CollideType: Int {
case Scene = 0
case Ceil = 1
case Floor = 2
case Ball = 3
case BoardStart = 4
func toMask()-> UInt32 {
return UInt32(1 << self.rawValue)
}
static func toMask(masks: [CollideType])-> UInt32 {
var toMask = UInt32(0)
for type in masks {
toMask |= type.toMask()
}
return toMask
}
Correct all code to match with CollideType definitions.
Correct this line in didBeginContact:
let bitMaskAAndB = contact.bodyA.categoryBitMask == CollisionTypes.Floor.rawValue && contact.bodyB.categoryBitMask == CollisionTypes.Ball.rawValue
with:
let bitMaskAAndB = contact.bodyA.categoryBitMask == CollideType.Floor.toMask() ? contact.bodyB.categoryBitMask : CollideType.Ball.toMask()
If you have correct all you will don't have yet this error:
// ball and ceil => ERROR

Simplifying collision and player death in SpriteKit

I want to add a bunch of different rocks and other dangerous objects that the player can collide with and die. How would I do this effectively? Now if I would copy paste these functions, it would surely work. But it seems like a huge amount of unnecessary code.
Sidenote: I'm very new to xcode, swift 2 & Sprite-kit.
func didBeginContact(contact: SKPhysicsContact) {
let firstBody : SKPhysicsBody = contact.bodyA
let secondBody : SKPhysicsBody = contact.bodyB
if ((firstBody.categoryBitMask == PhysicsCategory.Rock) && (secondBody.categoryBitMask == PhysicsCategory.Bullet) || (firstBody.categoryBitMask == PhysicsCategory.Bullet) && (secondBody.categoryBitMask == PhysicsCategory.Rock)) {
CollisionWithBullet(firstBody.node as! SKSpriteNode, Bullet: secondBody.node as! SKSpriteNode)
}
if ((firstBody.categoryBitMask == PhysicsCategory.Rock) && (secondBody.categoryBitMask == PhysicsCategory.Player) || (firstBody.categoryBitMask == PhysicsCategory.Player) && (secondBody.categoryBitMask == PhysicsCategory.Rock)) {
CollisionWithPlayer(firstBody.node as! SKSpriteNode, Player: secondBody.node as! SKSpriteNode)
}
}
func CollisionWithPlayer(Rock: SKSpriteNode, Player: SKSpriteNode){
let ScoreDefault = NSUserDefaults.standardUserDefaults()
ScoreDefault.setValue(Score, forKey: "Score")
ScoreDefault.synchronize()
let HighscoreDefault = NSUserDefaults.standardUserDefaults()
if (HighscoreDefault.valueForKey("Highscore") != nil){
Highscore = HighscoreDefault.valueForKey("Highscore") as! NSInteger
} else {
Highscore = 0
}
if (Score > Highscore){
let HighscoreDefault = NSUserDefaults.standardUserDefaults()
HighscoreDefault.setValue(Score, forKey: "Highscore")
}
self.view?.presentScene(EndScene())
ScoreLabel.removeFromSuperview()
}
So what you're likely looking for here is the bitwise OR operator and the bitwise AND operator.
With SpriteKit, physicsBodies can have multiple categories assigned to them. For instance, if we have the following categories set up:
enum CollisionCategories : UInt32 {
case Player = 1
case Enemy = 2
case Rock = 4
case Bullet = 8
}
we can set up the player category and contact bitmasks as follows:
let player = SKSpriteNode(color: UIColor.blackColor(), size: CGSize(width: 50, height: 50))
player.physicsBody = SKPhysicsBody(rectangleOfSize: player.size)
player.physicsBody?.categoryBitMask = CollisionCategories.Player.rawValue
player.physicsBody?.contactTestBitMask = CollisionCategories.Enemy.rawValue
and two enemy category and contact bitmasks as follows:
let rockEnemy = SKSpriteNode(color: UIColor.greenColor(), size: CGSize(width: 25, height: 25))
rockEnemy.physicsBody = SKPhysicsBody(rectangleOfSize: rockEnemy.size)
rockEnemy.physicsBody?.categoryBitMask = CollisionCategories.Enemy.rawValue | CollisionCategories.Rock.rawValue
rockEnemy.physicsBody?.contactTestBitMask = CollisionCategories.Player.rawValue
let bulletEnemy = SKSpriteNode(color: UIColor.redColor(), size: CGSize(width: 25, height: 25))
bulletEnemy.physicsBody = SKPhysicsBody(rectangleOfSize: bulletEnemy.size)
bulletEnemy.physicsBody?.categoryBitMask = CollisionCategories.Enemy.rawValue | CollisionCategories.Bullet.rawValue
bulletEnemy.physicsBody?.contactTestBitMask = CollisionCategories.Player.rawValue
Notice that on setting the category bitmasks, I am using the bitwise OR operator ('|'). This is a nice way of setting the bitmasks to two different categories at the same time. This way, a sprite can be both a rock and an enemy or a bullet and an enemy, etc.
See the image below for an idea of what is happening bitwise under the hood.
In our contact detection function, we can use the bitwise AND operator ('&') to see if our contact possesses a certain category.
func didBeginContact(contact: SKPhysicsContact) {
let firstBody : SKPhysicsBody = contact.bodyA
let secondBody : SKPhysicsBody = contact.bodyB
if (firstBody.categoryBitMask & CollisionCategories.Player.rawValue == CollisionCategories.Player.rawValue &&
secondBody.categoryBitMask & CollisionCategories.Enemy.rawValue == CollisionCategories.Enemy.rawValue) {
print("The collision was between the Player and an Enemy")
}
else if (firstBody.categoryBitMask & CollisionCategories.Enemy.rawValue == CollisionCategories.Enemy.rawValue &&
secondBody.categoryBitMask & CollisionCategories.Player.rawValue == CollisionCategories.Player.rawValue) {
print("The collision was between the Player and an Enemy")
}
}
This way, you can have enemies with multiple categories, but you can always do one check to see if a node is in fact an enemy, regardless of what other categories they might possess.

Collisions between sprites in SpriteKit

I'm making a game in XCode using SpriteKit. The game has a player and different types of projectiles that he has to avoid. When the player collides with the projectiles, the score changes and the projectile disappears. However, when two projectiles collide, they kind of bounce away.
I want to make that every time two projectiles collide, they act like nothing happened and they keep going in their original path. What should I do?
*Note: This is not the whole code, it's just what matters.
import SpriteKit
struct Physics {
static let player : UInt32 = 1
static let missileOne : UInt32 = 2
static let missileTwo : UInt32 = 3
}
class GameScene: SKScene, SKPhysicsContactDelegate {
var player = SKSpriteNode(imageNamed: "p1.png")
override func didMoveToView(view: SKView) {
physicsWorld.contactDelegate = self
player.position = CGPointMake(self.size.width/2, self.size.height/5)
player.physicsBody = SKPhysicsBody(rectangleOfSize: player.size)
player.physicsBody?.affectedByGravity = false
player.physicsBody?.dynamic = false
player.physicsBody?.categoryBitMask = Physics.player
player.physicsBody?.collisionBitMask = Physics.missileOne
player.physicsBody?.collisionBitMask = Physics.missileTwo
var missileOneTimer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("SpawnMissileOne"), userInfo: nil, repeats: true)
var missileTwoTimer = NSTimer.scheduledTimerWithTimeInterval(1.2, target: self, selector: Selector("SpawnMissileTwo"), userInfo: nil, repeats: true)
self.addChild(player)
}
//When contact happens
func didBeginContact(contact: SKPhysicsContact) {
var firstBody : SKPhysicsBody = contact.bodyA
var secondBody : SKPhysicsBody = contact.bodyB
if ((firstBody.categoryBitMask == Physics.player) && (secondBody.categoryBitMask == Physics.missileOne)) {
CollisionWithMissileOne(firstBody.node as SKSpriteNode, missileOne: secondBody.node as SKSpriteNode)
} else if ((firstBody.categoryBitMask == Physics.player) && (secondBody.categoryBitMask == Physics.missileTwo)){
CollisionWithMissileTwo(firstBody.node as SKSpriteNode, missileTwo: secondBody.node as SKSpriteNode)
} else if ((firstBody.categoryBitMask == Physics.missileOne)&&(secondBody.categoryBitMask == Physics.missileTwo)) {
CollisionBetweenMissiles(firstBody.node as SKSpriteNode, missileTwo: secondBody.node as SKSpriteNode)
}
}
//For Player and MissileOne
func CollisionWithMissileOne(player: SKSpriteNode, missileOne: SKSpriteNode) {
missileOne.removeFromParent()
}
//For Player and MissileTwo
func CollisionWithMissileOne(player: SKSpriteNode, missileTwo: SKSpriteNode) {
missileTwo.removeFromParent()
}
//For MissileOne and MissileTwo
func CollisionBetweenMissiles(missileOne: SKSpriteNode, missileTwo: SKSpriteNode) {
???WHAT SHOULD I CODE HERE???
}
}
The confusion is that the collisionBitMask is used to define which physicsBodies that interacts in the physicsModel. What you really want is contactTestBitmask.
Also your Physics doesn't return proper values to use for a Bit Mask. As pure Ints they should be 1,2,4,8 etc.
Here is your code changed to something that (hopefully) works, I've commented changes wherever I've made them.
struct Physics {
static let player : UInt32 = 1
static let missileOne : UInt32 = 2
static let missileTwo : UInt32 = 4 // to work properly as bit masks
}
This change is necessary if you want to check for contact with more than one type of physicsBody.categoryBitMask. Check out the player.physicsBody?.contactTestBitMask = ... in didMoveToView:
override func didMoveToView(view: SKView) {
physicsWorld.contactDelegate = self
// All your existing player-stuff is fine until...
// contactTest, not collision but contact, also: use bitwise OR
player.physicsBody?.contactTestBitMask = Physics.missileOne | Physics.missileTwo
self.addChild(player)
// It is not recommended to use NSTimer for SpriteKit, use SKActions instead
let missileOneWait = SKAction.waitForDuration(1)
let callSpawnOneAction = SKAction.runBlock({ self.spawnMissileOne() })
let missileOneRepeat = SKAction.repeatActionForever(SKAction.sequence([missileOneWait, callSpawnOneAction]))
runAction(missileOneRepeat)
let missileTwoWait = SKAction.waitForDuration(1.2)
let callSpawnTwoAction = SKAction.runBlock({ self.spawnMissileTwo() })
let missileTwoRepeat = SKAction.repeatActionForever(SKAction.sequence([missileTwoWait, callSpawnTwoAction]))
runAction(missileTwoRepeat)
}
Pretty much rewritten didBeginContact to something I believe reads and scales a lot better:
func didBeginContact(contact: SKPhysicsContact) {
var firstBody = contact.bodyA
var secondBody = contact.bodyB
// Rewritten with dynamic variables
var playerNode : SKSpriteNode? {
if firstBody.categoryBitMask == Physics.player {
return firstBody.node as? SKSpriteNode
} else if secondBody.categoryBitMask == Physics.player {
return secondBody.node as? SKSpriteNode
}
return nil
}
// If you want to handle contact between missiles you need to split this
// into two different variables
var missileNode : SKSpriteNode? {
let bitmask1 = firstBody.categoryBitMask
let bitmask2 = secondBody.categoryBitMask
if bitmask1 == Physics.missileOne || bitmask1 == Physics.missileTwo {
return firstBody.node as? SKSpriteNode
} else if bitmask2 == Physics.missileOne || bitmask2 == Physics.missileTwo {
return secondBody.node as? SKSpriteNode
}
return nil
}
if playerNode != nil {
collisionBetweenPlayer(playerNode, missile: missileNode)
}
}
Then you'll only need one function for contact between missile and player:
func collisionBetweenPlayer(player: SKSpriteNode?, missile: SKSpriteNode?) {
missile?.removeFromParent()
}

How may i detect contact and collision correctly? Swift iOS SKScene

The problem is i can't detect the collision //or contact in any way i have found on the internet
This is my code:
The declaration of my masks:
private let ballCategory : UInt32 = 0x1 << 0
private let holeCategory : UInt32 = 0x1 << 1
The adding of both the hole and the ball:
func addHole(#size : CGSize) {
let actionMoveDown = SKAction.moveToY(CGRectGetMidY(self.frame)-500, duration: 4.7)
let hole = shapedHoles()
let UT = UTIL()
var position:CGFloat
let randomPosition = UT.randomNumberWith(Min: 1, Max: 3)
switch randomPosition{
case 1:
position = CGRectGetMidX(self.frame)
case 2:
position = CGRectGetMidX(self.frame)+size.width
default:
position = CGRectGetMidX(self.frame)-(size.width)
}
var createdHole = hole.createHoleAtPosition(position: CGPointMake(position ,CGRectGetMaxY(self.frame) + (size.height/2)),size: size )//CGSizeMake(CGRectGetMaxX(self.frame)/3 - 10, 70)
createdHole.physicsBody = SKPhysicsBody(rectangleOfSize: createdHole.frame.size)
createdHole.physicsBody?.categoryBitMask = holeCategory
createdHole.physicsBody?.collisionBitMask = 0
createdHole.physicsBody?.contactTestBitMask = ballCategory
createdHole.physicsBody?.affectedByGravity = false
createdHole.physicsBody?.dynamic = false
lastHolePosition = randomPosition
createdHole .runAction(actionMoveDown)
self.addChild(createdHole)
}
func addSphere(){
let mainCharacterController = circle()
let character: (SKNode) = mainCharacterController.createCircleAtPosition(position: CGPointMake(CGRectGetMidX(self.frame), CGRectGetMinY(self.frame)+100))
character.physicsBody = SKPhysicsBody(circleOfRadius: character.frame.size.height/2)
character.physicsBody?.categoryBitMask = ballCategory
character.physicsBody?.collisionBitMask = 0
character.physicsBody?.contactTestBitMask = holeCategory
character.physicsBody?.affectedByGravity = false
character.physicsBody?.dynamic = false
self.addChild(character)
} func addHole(#size : CGSize) {
let actionMoveDown = SKAction.moveToY(CGRectGetMidY(self.frame)-500, duration: 4.7)
let hole = shapedHoles()
let UT = UTIL()
var position:CGFloat
let randomPosition = UT.randomNumberWith(Min: 1, Max: 3)
switch randomPosition{
case 1:
position = CGRectGetMidX(self.frame)
case 2:
position = CGRectGetMidX(self.frame)+size.width
default:
position = CGRectGetMidX(self.frame)-(size.width)
}
var createdHole = hole.createHoleAtPosition(position: CGPointMake(position ,CGRectGetMaxY(self.frame) + (size.height/2)),size: size )//CGSizeMake(CGRectGetMaxX(self.frame)/3 - 10, 70)
createdHole.physicsBody = SKPhysicsBody(rectangleOfSize: createdHole.frame.size)
createdHole.physicsBody?.categoryBitMask = holeCategory
createdHole.physicsBody?.collisionBitMask = 0
createdHole.physicsBody?.contactTestBitMask = ballCategory
createdHole.physicsBody?.affectedByGravity = false
createdHole.physicsBody?.dynamic = false
lastHolePosition = randomPosition
createdHole .runAction(actionMoveDown)
self.addChild(createdHole)
}
func addSphere(){
let mainCharacterController = circle()
let character: (SKNode) = mainCharacterController.createCircleAtPosition(position: CGPointMake(CGRectGetMidX(self.frame), CGRectGetMinY(self.frame)+100))
character.physicsBody = SKPhysicsBody(circleOfRadius: character.frame.size.height/2)
character.physicsBody?.categoryBitMask = ballCategory
character.physicsBody?.collisionBitMask = 0
character.physicsBody?.contactTestBitMask = holeCategory
character.physicsBody?.affectedByGravity = false
character.physicsBody?.dynamic = false
self.addChild(character)
}
And last but not least the didBeginContactMethod
func didBeginContact(contact: SKPhysicsContact) {
var firstBody: SKPhysicsBody!
var secondBody: SKPhysicsBody!
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
}
else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}
if (firstBody.categoryBitMask & holeCategory) != 0 &&
(secondBody.categoryBitMask & ballCategory) != 0 {
println("HO")
}
}
Thank you and hope you know what is happening, and if you need any extra code just comment it
You have to make sure that the SKScene subclass you are using also implements the SKPhysicsContactDelegate protocol. For example, it would look like this.
class MyScene : SKScene, SKPhysicsContactDelegate
Then you have to set your physics worlds contact delegate to yourself.
override init() {
self.physicsWorld.contactDelegate = self;
}
Tell me how this works out, but it should solve the problem and successfully allow you to listen in on collisions.
There is a couple things it might be. First you can try using an enum for the contact categories.
enum collisionBodies:UInt32 {
case ballCategory = 1
case holeCategory = 2
}
func Collisions() {
character.physicsBody.categoryBitMask = collisionBodies.ballCategory.rawValue
character.physicsBody.contactTestBitMask = collisionBodies.holeCategory.rawValue
character.physicsBody.collisionBitMask = 0
createdHole.physicsBody.categoryBitMask = collisionBodies.holeCategory.rawValue
createdHole.physicsBody.contactTestBitMask = collisionBodies.ballCategory.rawValue
createdHole.physicsBody.collisionBitMask = 0
}
Also try setting one of your physics bodies to dynamic = true or collisions will likely not work.
A better way to test for collisions in the didBeginContact function is to use a switch statement.
func didBeginContact(contact: SKPhysicsContact) {
let categoryMask = contact.BodyA.categoryBitMask | contact.BodyB.categoryBitMask
switch (categoryMask) {
case collisionBodies.holeCategory.rawValue | collisionBodies.ballCategory.rawValue:
//code to run when contact is detected
default:
return
}
}

Resources